Skip to content

Commit a8b65cb

Browse files
authored
Merge pull request aws-samples#3 from SoufanConsulting/elastic-ip-lambda
Elastic ip lambda
2 parents 40009ee + a7c230c commit a8b65cb

10 files changed

Lines changed: 123 additions & 66 deletions

File tree

lambda-elastic-ip-no-nat-gateway-cdk/cdk/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ node_modules
66
# CDK asset staging directory
77
.cdk.staging
88
cdk.out
9+
10+
template.yaml
11+
cdk.context.json

lambda-elastic-ip-no-nat-gateway-cdk/cdk/bin/cdk.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ const app = new cdk.App();
77

88
const patternStack = new LambdaElasticIpStack(app, 'LambdaElasticIpStack', {
99
env: {
10-
region: process.env.CDK_DEFAULT_REGION,
11-
account: process.env.CDK_DEFAULT_ACCOUNT,
10+
region: 'us-east-1' || process.env.CDK_DEFAULT_REGION,
11+
account: '199150394284' || process.env.CDK_DEFAULT_ACCOUNT,
1212
},
1313
});
1414

lambda-elastic-ip-no-nat-gateway-cdk/cdk/lib/cdk-stack.ts

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,35 @@ import * as cdk from 'aws-cdk-lib';
22
import { Construct } from 'constructs';
33

44
export interface LambdaElasticIpStackProps extends cdk.StackProps {
5-
availabilityZone?: string;
6-
cidrBlock?: string;
5+
vpcId?: string;
6+
subnetId?: string;
7+
securityGroupId?: string;
78
}
89

910
interface AssociateLambdaToElasticIpCRProps {
1011
elasticIP: cdk.aws_ec2.CfnEIP;
1112
vpc: cdk.aws_ec2.IVpc;
12-
publicSubnet: cdk.aws_ec2.Subnet;
13-
securityGroup: cdk.aws_ec2.SecurityGroup;
13+
publicSubnet: cdk.aws_ec2.ISubnet;
14+
securityGroup: cdk.aws_ec2.ISecurityGroup;
1415
functionName: string;
1516
}
1617
export class LambdaElasticIpStack extends cdk.Stack {
1718
constructor(scope: Construct, id: string, props: LambdaElasticIpStackProps) {
1819
super(scope, id, props);
1920

20-
const vpc = cdk.aws_ec2.Vpc.fromLookup(this, 'Default-VPC', { isDefault: true });
21-
const publicSubnet = new cdk.aws_ec2.Subnet(this, 'Elastic-IP-Lambda-Subnet', {
22-
vpcId: vpc.vpcId,
23-
availabilityZone: props.availabilityZone || 'us-east-1e',
24-
cidrBlock: props.cidrBlock || '172.31.96.0/20',
25-
mapPublicIpOnLaunch: true,
26-
});
27-
const routeTableId = vpc.publicSubnets[0].routeTable.routeTableId;
28-
const routeTableAssociation = new cdk.aws_ec2.CfnSubnetRouteTableAssociation(this, 'rt-s-association', {
29-
subnetId: publicSubnet.subnetId,
30-
routeTableId,
31-
});
32-
const securityGroup = new cdk.aws_ec2.SecurityGroup(this, 'Elastic-IP-Lambda-Security-Group', {
33-
vpc,
34-
allowAllOutbound: true,
35-
description:
36-
'This is a security group for a vpc attached lambda that uses elastic ip to have outbound communication without the need for a NAT solution',
37-
});
21+
const vpc = cdk.aws_ec2.Vpc.fromLookup(this, 'Default-VPC', { isDefault: !props.vpcId, vpcId: props.vpcId });
22+
const securityGroup = !!props.securityGroupId
23+
? cdk.aws_ec2.SecurityGroup.fromLookupById(this, 'Elastic-IP-Lambda-Security-Group', props.securityGroupId)
24+
: new cdk.aws_ec2.SecurityGroup(this, 'Elastic-IP-Lambda-Security-Group', {
25+
vpc,
26+
allowAllOutbound: true,
27+
description:
28+
'This is a security group for a vpc attached lambda that uses elastic ip to have outbound communication without the need for a NAT solution',
29+
});
30+
31+
const publicSubnet = !!props.subnetId
32+
? cdk.aws_ec2.Subnet.fromSubnetId(this, 'Elastic-IP-Lambda-Subnet', props.subnetId)
33+
: vpc.publicSubnets[0];
3834

3935
const publicFunction = new cdk.aws_lambda_nodejs.NodejsFunction(this, 'Lambda-With-Elastic-IP', {
4036
memorySize: 128,
@@ -55,7 +51,13 @@ export class LambdaElasticIpStack extends cdk.Stack {
5551

5652
const elasticIP = new cdk.aws_ec2.CfnEIP(this, 'Lambda-Elastic-Ip', {});
5753

58-
this.associateLambdaToElasticIpCR({ elasticIP, vpc, publicSubnet, securityGroup, functionName: publicFunction.functionName });
54+
this.associateLambdaToElasticIpCR({
55+
elasticIP,
56+
vpc,
57+
publicSubnet,
58+
securityGroup,
59+
functionName: publicFunction.functionName,
60+
});
5961
}
6062

6163
private associateLambdaToElasticIpCR({ elasticIP, publicSubnet, securityGroup, vpc, functionName }: AssociateLambdaToElasticIpCRProps) {
@@ -78,7 +80,7 @@ export class LambdaElasticIpStack extends cdk.Stack {
7880
associateElasticIpFunctionCR.addToRolePolicy(
7981
new cdk.aws_iam.PolicyStatement({
8082
effect: cdk.aws_iam.Effect.ALLOW,
81-
actions: ['ec2:DescribeAddresses', 'ec2:AssociateAddress', 'ec2:DescribeNetworkInterfaces'],
83+
actions: ['ec2:AssociateAddress', 'ec2:DescribeNetworkInterfaces'],
8284
resources: ['*'],
8385
}),
8486
);

lambda-elastic-ip-no-nat-gateway-cdk/cdk/package.json

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,27 @@
88
"build": "tsc",
99
"watch": "tsc -w",
1010
"test": "jest",
11-
"cdk": "cdk"
11+
"esbuild": "rm -rf dist && esbuild ./src/lambdas/* --bundle --entry-names=[dir]/[name]/index --sourcemap --platform=node --target=node18.14 --outdir=dist",
12+
"package": "cd dist && for f in * ; do ([ -d \"$f\" ] && cd $f && zip ../$f.zip *) ; done",
13+
"bundle": "npm run esbuild && npm run package",
14+
"local-synth": "npm run build && cdk synth --no-staging > template.yaml",
15+
"deploy": "cdk deploy",
16+
"local-synth-and-deploy": "npm run local-synth && npm run deploy",
17+
"destroy": "cdk destroy"
1218
},
1319
"devDependencies": {
14-
"@types/jest": "^29.4.0",
15-
"@types/node": "18.14.6",
16-
"jest": "^29.5.0",
17-
"ts-jest": "^29.0.5",
18-
"aws-cdk": "2.80.0",
20+
"@types/jest": "^29.5.4",
21+
"@types/node": "20.5.7",
22+
"@types/source-map-support": "^0.5.7",
23+
"jest": "^29.6.4",
24+
"ts-jest": "^29.1.1",
25+
"aws-cdk": "2.94.0",
26+
"esbuild": "^0.15.14",
1927
"ts-node": "^10.9.1",
20-
"typescript": "~4.9.5"
28+
"typescript": "^5.2.2"
2129
},
2230
"dependencies": {
23-
"aws-cdk-lib": "2.80.0",
31+
"aws-cdk-lib": "2.94.0",
2432
"constructs": "^10.0.0",
2533
"source-map-support": "^0.5.21"
2634
}

lambda-elastic-ip-no-nat-gateway-cdk/cdk/src/lambdas/associate-lambda-elastic-ip-cr.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { Handler } from 'aws-lambda';
2-
import { EC2Client, AssociateAddressCommand, DescribeAddressesCommand, DescribeNetworkInterfacesCommand } from '@aws-sdk/client-ec2'; // ES Modules import
2+
import { EC2Client, AssociateAddressCommand, DescribeNetworkInterfacesCommand } from '@aws-sdk/client-ec2'; // ES Modules import
33
import { AssociateLambdaElasticIpEvent } from '../types/associate-lambda-elastic-ip-event';
44
const client = new EC2Client();
55

66
export const handler: Handler = async (event: AssociateLambdaElasticIpEvent) => {
7-
console.log('Associating Lambda to Elastic IP Custom Resource:', event);
8-
console.log('environment', process.env);
7+
console.log('Associating Lambda to Elastic IP Custom Resource Event:', event);
8+
console.log('Environment', process.env);
99
const allocationId = process.env.ELASTIC_IP_ALLOCATION_ID;
1010
if (!allocationId) {
1111
throw new Error(`Error allocation id cannot be null or empty. '${allocationId}'`);
1212
}
13-
console.log(`allocation id from env: ${allocationId}`);
13+
console.log(`Allocation id from env: ${allocationId}`);
1414
try {
15-
console.log('Fetching Lambda network interface ID associated with the elastic ip...');
15+
console.log('Fetching lambda network interface ID associated with the elastic ip...');
1616

1717
const DescribeNetworkInterfacesCommandRequest = {
1818
Filters: [
@@ -56,13 +56,17 @@ export const handler: Handler = async (event: AssociateLambdaElasticIpEvent) =>
5656
new DescribeNetworkInterfacesCommand(DescribeNetworkInterfacesCommandRequest),
5757
);
5858
console.log('DescribeNetworkInterfacesCommandResponse:', JSON.stringify(DescribeNetworkInterfacesCommandResponse, null, 2));
59+
const returnedNetworkInterfaces = DescribeNetworkInterfacesCommandResponse.NetworkInterfaces;
60+
if (!returnedNetworkInterfaces?.length) {
61+
throw new Error(`No network interface is associated with this lambda function ${event.functionName}`);
62+
}
5963

6064
console.log('Associating Lambda to Elastic IP...');
6165

6266
const AssociateAddressRequest = {
6367
AllocationId: allocationId,
6468
DryRun: false,
65-
NetworkInterfaceId: DescribeNetworkInterfacesCommandResponse.NetworkInterfaces![0].NetworkInterfaceId,
69+
NetworkInterfaceId: returnedNetworkInterfaces[0].NetworkInterfaceId,
6670
};
6771

6872
console.log('AssociateAddressRequest:', AssociateAddressRequest);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Handler } from 'aws-cdk-lib/aws-lambda';
2+
import { httpsGet } from '../utils/https';
3+
4+
export const handler: Handler = async () => {
5+
console.log('calling a 3rd party api over the internet to fetch a random VIN...');
6+
const thirdPartyUrl = 'https://randomvin.com/getvin.php?type=real';
7+
8+
try {
9+
const response = await httpsGet(thirdPartyUrl);
10+
console.log(`your random VIN is: ${response}`);
11+
return response;
12+
} catch (error: any) {
13+
console.error(`Error Fetching VIN: ${error.message}`);
14+
throw error;
15+
}
16+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "src",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"dependencies": {
10+
"aws-lambda": "^1.0.7",
11+
"@aws-sdk/client-ec2": "^3.405.0"
12+
},
13+
"devDependencies": {
14+
"@types/aws-lambda": "^8.10.119",
15+
"@types/node": "20.5.7",
16+
"ts-node": "^10.9.1",
17+
"typescript": "^5.2.2"
18+
},
19+
"author": "",
20+
"license": "ISC"
21+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"module": "commonjs",
5+
"lib": ["DOM", "es2020"],
6+
"declaration": true,
7+
"strict": true,
8+
"noImplicitAny": true,
9+
"strictNullChecks": true,
10+
"noImplicitThis": true,
11+
"alwaysStrict": true,
12+
"noUnusedLocals": false,
13+
"noUnusedParameters": false,
14+
"noImplicitReturns": true,
15+
"noFallthroughCasesInSwitch": false,
16+
"inlineSourceMap": true,
17+
"inlineSources": true,
18+
"experimentalDecorators": true,
19+
"strictPropertyInitialization": false,
20+
"typeRoots": ["./node_modules/@types"]
21+
},
22+
"exclude": ["node_modules", "cdk.out"]
23+
}

lambda-elastic-ip-no-nat-gateway-cdk/cdk/src/lambdas/vip-api-lambda.ts renamed to lambda-elastic-ip-no-nat-gateway-cdk/cdk/src/utils/https.ts

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { Handler } from 'aws-cdk-lib/aws-lambda';
21
import * as https from 'https';
32

4-
async function httpsGet(url: string): Promise<string> {
3+
export async function httpsGet(url: string): Promise<string> {
54
try {
65
const response = await new Promise<any>((resolve, reject) => {
76
const request = https.request(url, resolve);
@@ -29,17 +28,4 @@ async function httpsGet(url: string): Promise<string> {
2928
console.error(`Error: ${error.message}`);
3029
throw error;
3130
}
32-
}
33-
34-
export const handler: Handler = async () => {
35-
console.log('fetching random VIN...');
36-
const url = 'https://randomvin.com/getvin.php?type=real';
37-
// Call the async function
38-
try {
39-
const response = await httpsGet(url);
40-
console.log(`your random VIN is: ${response}`);
41-
} catch (error: any) {
42-
console.error(`Error Fetching VIN: ${error.message}`);
43-
throw error;
44-
}
45-
};
31+
}

lambda-elastic-ip-no-nat-gateway-cdk/cdk/tsconfig.json

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
"compilerOptions": {
33
"target": "ES2020",
44
"module": "commonjs",
5-
"lib": [
6-
"es2020"
7-
],
5+
"lib": ["es2020", "DOM"],
86
"declaration": true,
97
"strict": true,
108
"noImplicitAny": true,
@@ -19,12 +17,8 @@
1917
"inlineSources": true,
2018
"experimentalDecorators": true,
2119
"strictPropertyInitialization": false,
22-
"typeRoots": [
23-
"./node_modules/@types"
24-
]
20+
"typeRoots": ["./node_modules/@types"],
21+
"outDir": "dist"
2522
},
26-
"exclude": [
27-
"node_modules",
28-
"cdk.out"
29-
]
23+
"exclude": ["node_modules", "cdk.out", "dist"]
3024
}

0 commit comments

Comments
 (0)