Skip to content

Commit 8a44b8d

Browse files
author
ikim23
committed
init
0 parents  commit 8a44b8d

11 files changed

+344
-0
lines changed

Diff for: .editorconfig

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Unix-style newlines with a newline ending every file
7+
[*]
8+
end_of_line = lf
9+
insert_final_newline = true
10+
indent_style = space
11+
indent_size = 2
12+
13+
# 2 space indentation
14+
[{*.js,*.json,*.yml,*.md}]
15+
indent_style = space
16+
indent_size = 2
17+
18+
[Makefile]
19+
indent_style = tab
20+
indent_size = 4

Diff for: .env.template

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
AWS_ACCESS_KEY_ID=add_me
2+
AWS_SECRET_ACCESS_KEY=add_me
3+
STAGE=add_me
4+
REGION=add_me

Diff for: .eslintrc

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "airbnb-base",
3+
"rules": {
4+
"no-underscore-dangle": [
5+
"error",
6+
{
7+
"allowAfterThis": true
8+
}
9+
]
10+
}
11+
}

Diff for: .gitignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# package directories
2+
node_modules
3+
jspm_packages
4+
5+
# Serverless directories
6+
.serverless
7+
8+
.env
9+
!.env.template

Diff for: Dockerfile

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM node:6.10
2+
3+
# create project directory
4+
RUN mkdir -p /usr/src/app
5+
WORKDIR /usr/src/app
6+
7+
# copy project files fo WORKDIR
8+
COPY . .
9+
10+
# install AWS CLI
11+
# To configure AWS CLI setup environment variables:
12+
# AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION
13+
RUN apt-get update
14+
RUN apt-get -y install python-setuptools python-dev build-essential python-pip
15+
RUN pip install --upgrade pip
16+
RUN pip install awscli --upgrade --user
17+
18+
ENV PATH=~/.local/bin:$PATH
19+
20+
# install dependencies
21+
RUN npm i --silent -g serverless

Diff for: README.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# AWS Lambda - Static outgoing IP address
2+
3+
This repository is created according to article [AWS Lambdas with a static outgoing IP](http://techblog.financialengines.com/2016/09/26/aws-lambdas-with-a-static-outgoing-ip/) by Ivonne Roberts. By using this repository you do not have to create all AWS resources by hand, but you can let AWS CloudFormation to do it for you. To see CloudFormation config open `serverless.yml` file. Steps mentioned in the article are marked in this file, so that it is easier to follow.
4+
5+
## Requirements:
6+
7+
- curl
8+
- docker
9+
- docker-compose
10+
11+
## Usage:
12+
13+
Create `.env` file:
14+
```
15+
mv .env.template .env
16+
```
17+
Set environment variable values in `.env` file:
18+
|Variable|Description|
19+
|-|-|
20+
|AWS_ACCESS_KEY_ID|Access key ID for serverless framework|
21+
|AWS_SECRET_ACCESS_KEY|Access key for serverless framework|
22+
|STAGE|name of deployment stage (e.g dev)|
23+
|REGION|deployment region (e.g us-west-1)|
24+
25+
Clone repository:
26+
```
27+
git clone https://github.com/ikim23/aws-lambda-static-ip.git
28+
```
29+
Install NPM modules:
30+
```
31+
docker-compose run install
32+
```
33+
Deploy app to AWS:
34+
```
35+
docker-compose run deploy
36+
```
37+
Trigger caller function to get Elastic IP address (static IP):
38+
```
39+
curl -XGET https://<API_IP>.execute-api.<REGION>.amazonaws.com/<STAGE/call
40+
```

Diff for: docker-compose.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
version: '2'
2+
3+
services:
4+
5+
shell:
6+
build:
7+
context: .
8+
dockerfile: Dockerfile
9+
image: aws-lambda-static-ip
10+
volumes:
11+
- .:/usr/src/app
12+
env_file: .env
13+
command: bash
14+
15+
install:
16+
extends:
17+
service: shell
18+
command: npm i --silent
19+
20+
deploy:
21+
extends:
22+
service: shell
23+
command: sls deploy

Diff for: functions/caller/caller.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const request = require('request-promise-native');
2+
3+
module.exports.handler = (event, context, callback) => {
4+
request({
5+
method: 'GET',
6+
uri: process.env.URI,
7+
}).then((data) => {
8+
const { ip } = JSON.parse(data);
9+
const msg = `Your static ip address is: ${ip}`;
10+
console.log(msg);
11+
callback(null, {
12+
statusCode: 200,
13+
body: msg,
14+
});
15+
}).catch((err) => {
16+
console.error(err);
17+
callback(err);
18+
});
19+
};

Diff for: functions/logger/logger.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
module.exports.handler = (event, context, callback) => {
3+
const { sourceIp } = event;
4+
console.log(`Received request from ip: ${sourceIp}`);
5+
callback(null, {
6+
ip: sourceIp,
7+
});
8+
};

Diff for: package.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "aws-lambda-static-ip",
3+
"version": "1.0.0",
4+
"description": "AWS Lambda - Static IP",
5+
"main": "index.js",
6+
"scripts": {
7+
"lint": "eslint --ext .js functions/"
8+
},
9+
"keywords": [],
10+
"author": "ikim23",
11+
"license": "ISC",
12+
"dependencies": {
13+
"request": "^2.81.0",
14+
"request-promise-native": "^1.0.4"
15+
},
16+
"devDependencies": {
17+
"eslint": "^3.19.0",
18+
"eslint-config-airbnb-base": "^11.1.3",
19+
"eslint-plugin-import": "^2.2.0"
20+
}
21+
}

Diff for: serverless.yml

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
service: aws-lambda-static-ip
2+
3+
provider:
4+
name: aws
5+
runtime: nodejs6.10
6+
stage: ${env:STAGE}
7+
region: ${env:REGION}
8+
versionFunctions: false
9+
memorySize: 512
10+
timeout: 10
11+
vpc:
12+
securityGroupIds:
13+
- Fn::GetAtt: [VPCStaticIP, DefaultSecurityGroup]
14+
subnetIds:
15+
- Ref: SubnetPrivate
16+
iamRoleStatements:
17+
- Effect: Allow
18+
Action:
19+
- ec2:CreateNetworkInterface
20+
- ec2:DeleteNetworkInterface
21+
- ec2:DescribeNetworkInterfaces
22+
Resource: '*'
23+
24+
functions:
25+
logger:
26+
handler: functions/logger/logger.handler
27+
events:
28+
- http:
29+
path: log
30+
method: get
31+
integration: lambda
32+
request:
33+
template:
34+
application/json: '{ "sourceIp" : "$context.identity.sourceIp" }'
35+
caller:
36+
environment:
37+
URI:
38+
Fn::Join: ['', [https://, Ref: ApiGatewayRestApi, '.execute-api.${self:provider.region}.amazonaws.com/${self:provider.stage}/log']]
39+
handler: functions/caller/caller.handler
40+
events:
41+
- http:
42+
path: call
43+
method: get
44+
45+
resources:
46+
Resources:
47+
# Resources created according to blog post:
48+
# http://techblog.financialengines.com/2016/09/26/aws-lambdas-with-a-static-outgoing-ip/
49+
50+
# Step 1: Create a new VPC
51+
VPCStaticIP:
52+
Type: AWS::EC2::VPC
53+
Properties:
54+
CidrBlock: 11.0.0.0/16
55+
Tags:
56+
- Key: Name
57+
Value: ${self:service}-${self:provider.stage}-vpc
58+
59+
# Step 2: Create 2 Subnets
60+
SubnetPublic:
61+
Type: AWS::EC2::Subnet
62+
Properties:
63+
AvailabilityZone: ${self:provider.region}b
64+
CidrBlock: 11.0.0.0/24
65+
Tags:
66+
- Key: Name
67+
Value: ${self:service}-${self:provider.stage}-public-subnet
68+
VpcId:
69+
Ref: VPCStaticIP
70+
71+
SubnetPrivate:
72+
Type: AWS::EC2::Subnet
73+
Properties:
74+
AvailabilityZone: ${self:provider.region}b
75+
CidrBlock: 11.0.1.0/24
76+
Tags:
77+
- Key: Name
78+
Value: ${self:service}-${self:provider.stage}-private-subnet
79+
VpcId:
80+
Ref: VPCStaticIP
81+
82+
# Step 3: Create an Internet Gateway
83+
InternetGateway:
84+
Type: AWS::EC2::InternetGateway
85+
Properties:
86+
Tags:
87+
- Key: Name
88+
Value: ${self:service}-${self:provider.stage}-igw
89+
90+
# Attach Internet Gateway to VPC
91+
VPCGatewayAttachment:
92+
Type: AWS::EC2::VPCGatewayAttachment
93+
Properties:
94+
InternetGatewayId:
95+
Ref: InternetGateway
96+
VpcId:
97+
Ref: VPCStaticIP
98+
99+
# Step 4: Create a public Route Table and Assign it to our public route
100+
RouteTablePublic:
101+
Type: AWS::EC2::RouteTable
102+
Properties:
103+
VpcId:
104+
Ref: VPCStaticIP
105+
Tags:
106+
- Key: Name
107+
Value: ${self:service}-${self:provider.stage}-public-route
108+
109+
RoutePublic:
110+
Type: AWS::EC2::Route
111+
Properties:
112+
DestinationCidrBlock: 0.0.0.0/0
113+
GatewayId:
114+
Ref: InternetGateway
115+
RouteTableId:
116+
Ref: RouteTablePublic
117+
118+
SubnetRouteTableAssociationPublic:
119+
Type: AWS::EC2::SubnetRouteTableAssociation
120+
Properties:
121+
RouteTableId:
122+
Ref: RouteTablePublic
123+
SubnetId:
124+
Ref: SubnetPublic
125+
126+
# Step 5: Create a NAT Gateway
127+
# Before creating NAT Gateway, we need to create Elastic IP with vpc scope
128+
EIP:
129+
Type: AWS::EC2::EIP
130+
Properties:
131+
Domain: vpc
132+
133+
NatGateway:
134+
Type: AWS::EC2::NatGateway
135+
Properties:
136+
AllocationId:
137+
Fn::GetAtt: [EIP, AllocationId]
138+
SubnetId:
139+
Ref: SubnetPublic
140+
141+
# In tutorial NAT Gateway is attached as default route 0.0.0.0/0 in main Route Table.
142+
# Main Route Table is created implicitely during VPC creation and CloudFormation
143+
# has no access to its ID. To overcome this limitation we create additional Route Table.
144+
RouteTablePrivate:
145+
Type: AWS::EC2::RouteTable
146+
Properties:
147+
VpcId:
148+
Ref: VPCStaticIP
149+
Tags:
150+
- Key: Name
151+
Value: ${self:service}-${self:provider.stage}-private-route
152+
153+
RoutePrivate:
154+
Type: AWS::EC2::Route
155+
Properties:
156+
DestinationCidrBlock: 0.0.0.0/0
157+
NatGatewayId:
158+
Ref: NatGateway
159+
RouteTableId:
160+
Ref: RouteTablePrivate
161+
162+
SubnetRouteTableMainAssociationPrivate:
163+
Type: AWS::EC2::SubnetRouteTableAssociation
164+
Properties:
165+
RouteTableId:
166+
Ref: RouteTablePrivate
167+
SubnetId:
168+
Ref: SubnetPrivate

0 commit comments

Comments
 (0)