Skip to content

Commit 350fd1d

Browse files
committed
removed function name from filter
added documentation
1 parent b11e7c6 commit 350fd1d

4 files changed

Lines changed: 48 additions & 13 deletions

File tree

lambda-elastic-ip-no-nat-gateway-cdk/README.md

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,38 @@ app.synth();
6969

7070

7171
## Use Case
72-
You have a lambda function that requires internet access to make api calls to 3rd party vendors but you need a dedicated IP to be whitelisted by the 3rd party vendors.
72+
This solution will help you, if your use case tick the following bullet points:
73+
- You are trying to connect to a 3rd party API
74+
- 3rd party API requires whitelisting a static IP of its clients
75+
- You want to use Lambda functions
76+
77+
#### Current Industry Standard Solution
78+
Place your Lambda in *private* subnet. Place a NAT Solution (NAT Gateway/NAT Instance) in a *public* subnet and attach an AWS Elastic IP to the NAT Solution.
79+
80+
This solution is actually great and offers HA (with NAT Gateways) and scalable. Exactly what you need for production environments
81+
82+
Solution is explained in details [here](https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/generate-a-static-outbound-ip-address-using-a-lambda-function-amazon-vpc-and-a-serverless-architecture.html)
83+
###### *However...*
84+
85+
NAT Gateways come at a cost (**~$33/month per gateway**). To make NAT Gateway Highly Available & Scalable you need to provision 1 NAT Gateway per subnet.
86+
So, if you have 3 subnets the cost will be:
87+
88+
**3 * $33 = ~$100/month**
89+
Now this is nearly an unavoidable expense for your production environments, as scalability & HA are requirements.
90+
91+
However, if you have 3 non-prod environments (DEV, QA, STAGE...) the cost of these environments will be **3 accounts * $100 = ~$300/month**. High Availability is not probably a requirement for these environments.
92+
93+
So, This solution will help you save on NAT costs when scalability & HA are not required.
94+
7395
## How it works
7496

75-
This pattern allows you to assign your lambda function a static public IP address that you can use to interact with APIs that require whitelisted IPs without the need to provision a NAT Gateway. Therefore, this pattern will save almost **$33/month** in NAT Gateway costs.
97+
This pattern kick things off by provisioning an Elastic IP in your account.
98+
As you may know, AWS manages the provisioning of ENIs for each Lambda provisioned within an AWS VPC. Using CDK code we won't have access to that ENI. However, once that ENI is provisioned it can be accessed. So the pattern will create a Custom Resource that taps into that ENI and make a CLI call (using the SDK) to attach it to the Elastic IP.
99+
100+
Now that the lambda has an elastic IP associated to its network interface, you can copy that Elastic IP and whitelist it with your 3rd party vendors so the lambda can connect to it.
101+
102+
#### Main Benefit:
103+
Saving on NAT Gateway costs **$33/month per subnet per environment-account** when the solution does not need to be very scalable or highly available
76104

77105

78106
The following resources will be provisioned:
@@ -81,10 +109,23 @@ The following resources will be provisioned:
81109
- An Elastic IP to associate with the Lambda function
82110
- A custom resource with Lambda function to associate the Elastic IP with the test lambda's ENI
83111

84-
Since AWS manages the provisioning of any Lambda ENI, we cannot access that ENI in CDK code. Therefore, to automate the process, we have to associate the Elastic IP with the ENI in a custom resource after the deployment occurs and the ENI is provisioned.
112+
85113

86114
##### **NOTE:** This pattern is best suited for non-production environments since it is not multi-AZ nor highly scalable.
87115

116+
### Limitations To Be Aware Of
117+
118+
- Elastic IPs: 5 per Region [VPC Quotes](https://docs.aws.amazon.com/vpc/latest/userguide/amazon-vpc-limits.html)
119+
- Network interfaces: 5,000 per Region
120+
- HENIs (Hyperplane ENIs) soft limit of 250 per VPC and the hard limit is 350 HENIs per VPC [link](https://aws.plainenglish.io/dealing-with-you-have-exceeded-the-maximum-limit-for-hyperplane-enis-for-your-account-223147e7ab64#b6c5)
121+
- Hyperplane ENI is a special type of ENI used by AWS Lambda to cut off on the start up time of ENI provisioning and provide the capability of sharing the underlying network hardware for all Lambdas in *subnet+securityGroup* combination (for more [info](https://aws.amazon.com/blogs/compute/announcing-improved-vpc-networking-for-aws-lambda-functions/))
122+
123+
- There is a limit of 65K on connections for a single Hyperplane ENI. So, if group of Lambdas in the same Subnet+SecurityGroup combination create more than 65K connections at the same time, AWS will provision a new ENI for the connection number 65001 [Lambda ENI](https://docs.aws.amazon.com/lambda/latest/dg/foundation-networking.html#foundation-nw-eni-create)(Thanks to Yan Cui for pointing that out in the [comment on this video](https://www.youtube.com/watch?v=yV1TGDYR3qU&t=92s&ab_channel=YanCui))
124+
125+
### Pricing Notes
126+
You are still charged for data transfer expenses in and out of the ENI (~$0.09/GB in each direction) [data-transfer pricing](https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer)
127+
128+
88129
## Testing
89130

90131
To test this pattern, you must use both the AWS Console and the AWS CLI.

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ interface AssociateLambdaToElasticIpCRProps {
1212
vpc: cdk.aws_ec2.IVpc;
1313
publicSubnet: cdk.aws_ec2.ISubnet;
1414
securityGroup: cdk.aws_ec2.ISecurityGroup;
15-
functionName: string;
1615
}
1716
export class LambdaElasticIpStack extends cdk.Stack {
1817
constructor(scope: Construct, id: string, props: LambdaElasticIpStackProps) {
@@ -56,11 +55,10 @@ export class LambdaElasticIpStack extends cdk.Stack {
5655
vpc,
5756
publicSubnet,
5857
securityGroup,
59-
functionName: publicFunction.functionName,
6058
});
6159
}
6260

63-
private associateLambdaToElasticIpCR({ elasticIP, publicSubnet, securityGroup, vpc, functionName }: AssociateLambdaToElasticIpCRProps) {
61+
private associateLambdaToElasticIpCR({ elasticIP, publicSubnet, securityGroup, vpc }: AssociateLambdaToElasticIpCRProps) {
6462
const associateElasticIpFunctionCR = new cdk.aws_lambda_nodejs.NodejsFunction(this, 'Associate-Elastic-IP-CR', {
6563
memorySize: 128,
6664
handler: 'handler',
@@ -97,7 +95,6 @@ export class LambdaElasticIpStack extends cdk.Stack {
9795
availabilityZone: publicSubnet.availabilityZone,
9896
allocationId: elasticIP.attrAllocationId,
9997
staticIp: elasticIP.ref,
100-
functionName,
10198
date: new Date(),
10299
}),
103100
},

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ export const handler: Handler = async (event: AssociateLambdaElasticIpEvent) =>
4040
Name: 'status',
4141
Values: ['in-use'],
4242
},
43-
{
44-
Name: 'description',
45-
Values: [`AWS Lambda VPC ENI-${event.functionName}*`],
46-
},
4743
],
4844
AllocationIds: [allocationId],
4945
MaxResults: 10,
@@ -58,7 +54,9 @@ export const handler: Handler = async (event: AssociateLambdaElasticIpEvent) =>
5854
console.log('DescribeNetworkInterfacesCommandResponse:', JSON.stringify(DescribeNetworkInterfacesCommandResponse, null, 2));
5955
const returnedNetworkInterfaces = DescribeNetworkInterfacesCommandResponse.NetworkInterfaces;
6056
if (!returnedNetworkInterfaces?.length) {
61-
throw new Error(`No network interface is associated with this lambda function ${event.functionName}`);
57+
throw new Error(
58+
`No network interface is associated with this subnet + securityGroup combination (${event.subnetId}, ${event.securityGroupId})`,
59+
);
6260
}
6361

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

lambda-elastic-ip-no-nat-gateway-cdk/cdk/src/types/associate-lambda-elastic-ip-event.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ export type AssociateLambdaElasticIpEvent = {
55
allocationId: string;
66
staticIp: string;
77
availabilityZone: string;
8-
functionName: string;
98
};

0 commit comments

Comments
 (0)