Static IP for Lambda: ingress, egress and bypassing the dreaded NAT Gateway

Yan Cui

I help clients go faster for less using serverless technologies.

This article is brought to you by

Is your CI build step taking too long? Try Depot for free today and experience up to 40x faster build speed!

Unlock faster CI for FREE

Many vendors require you to have a static IP address for your application. Such that all requests to their API must originate from an allow-list of IP addresses. This means we need to force egress traffic from our Lambda functions through a static IP address.

Sometimes, they even mandate that you use a static IP address for ingress traffic, too, so they can communicate with your system through a trusted IP address. These practices are a throwback to the heyday of on-premise software and represent a hurdle for modern, cloud-native applications. But nonetheless, sometimes we are stuck with a vendor and have to do what they ask…

So, for those who are building serverless applications and struggling with these archaic requirements, I hope this post offers you some solace.

Static IP for egress

The “proper” way to assign a static IP for egress traffic is to:

  1. Put the Lambda function inside a private subnet in a VPC
  2. Assign a NAT Gateway to the VPC. This grants internet access to the resources inside the private subnets.
  3. Attach an Elastic IP to the NAT Gateway instance. This associates a static, public IP address to the NAT Gateway.

Now you can add the static IP address to the 3rd party service’s allow-list.

I also published a YouTube video [1] about this topic.

The video also discussed the cost overhead for this setup.

Because a NAT Gateway has an update cost of ~$33/month even if you don’t use it.

In the comments, kl9560 gave me an ingenious idea on how to bypass NAT Gateway altogether and do away with the associated costs.

Bypassing the NAT Gateway for egress

Lambda functions run on bare-metal EC2 instances managed by the AWS Lambda team. These EC2 instances run inside an AWS-managed VPC. When you connect a function to your own VPC, a Hyperplane ENI is created to allow the function access to resources within your VPC.

You can read more about how private networking works with Lambda on this official documentation page [2].

Note this important paragraph:

“Lambda creates a Hyperplane ENI when you define a unique subnet plus security group combination for a VPC-enabled function in an account. Lambda reuses the Hyperplane ENI for other VPC-enabled functions in your account that use the same subnet and security group combination.”

This means that (caveats aside) we can identify the ENI for a Lambda function by its subnet and security group configurations.

Take this Lambda function, for example, and this is its VPC configuration.

It’s placed within a pair of public subnets, with a route to the public internet via an Internet Gateway. Internet Gateway is free to use, but you still need to pay the data transfer costs.

This is NOT how you would normally configure a Lambda function in VPC. This setup does not grant the function access to the internet because it doesn’t have a public IP address.

But remember what I said earlier about finding the ENI for a function based on its subnet and security group settings?

If we go to the EC2 console and look under “Network Interfaces”. We can find the ENIs the function will use – one for each subnet.

Now, we can create and associate two Elastic IPs with these two ENIs. This will give the function access to the Internet without needing a NAT Gateway. The egress traffic will originate from one of the two Elastic IPs that are associated with the ENIs.

This approach removes the need for NAT Gateway by taking advantage (ahem… exploiting) of a piece of Lambda implementation detail.

As always, there are dangers when you depend on implementation details within a service and walk outside the well-trodden paths.

This approach breaks down in two ways:

  1. ENIs are created for each unique combination of subnet and security group. If you change either configuration on a function, you will get a new set of ENIs. You’d have to repeat the process of associating the new ENIs to your elastic IPs. This switchover would require downtime as it’s not an atomic operation. During this, the function would lose access to the Internet. But you can minimize this time window through automation—e.g., using a CloudFormation custom resource.
  2. There’s a limit of 65,000 connections per ENI. When the connection limit is reached, Lambda would create a new ENI. In this really unlikely event, some instances of the function would use a different ENI because they are the 65001st or 65002nd connection.

These are not necessarily showstoppers. However, this approach might also have potential security risks. I can’t think of any myself, so please let me know if you do!

Overall, I don’t recommend using this approach in production. But it can be a helpful trick to help you save on those dreaded NAT Gateway costs in the dev environments. Also, it’s worth noting that AWS is charging $0.005 per hour for every public IPv4 address since February 1st, 2024. That works out to be ~$3.6 per month per IPv4 address. So, if you create lots of Elastic IPs for this approach, it might be more expensive than just using NAT Gateway.

Static IP for ingress

As stated at the start of this post, some vendors also require a static IP for callbacks/webhooks. This can be tricky because neither the API Gateway nor the Application Load Balancer (ALB) provide static IP. And Lambda doesn’t work with the Network Load Balancer (NLB).

Instead, you can use AWS Global Accelerator [3] in front of the ALB.

There are additional costs for Global Accelerator:

  • $0.025/hour
  • There is a data transfer premium fee in addition to the regular data transfer costs. This varies by destination, so please see the official pricing page [4] for more details.

Despite the additional moving part and the associated costs, Global Accelerator is the easiest way to create static IPs for ingress traffic for Lambda.

Links

[1] AWS Lambda: How to use static IP address for egress

[2] Lambda: Private networking with VPC

[3] AWS Global Accelerator

[4] AWS Global Accelerator pricing

Related posts

How to create IP-protected endpoints with API Gateway and Lambda

How to set up geofencing and IP allow-list for Cognito user pool

How to choose the right API Gateway auth method

Whenever you’re ready, here are 4 ways I can help you:

  1. Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
  2. Do you want to know how to test serverless architectures with a fast dev & test loop? Check out my latest course, Testing Serverless Architectures and learn the smart way to test serverless.
  3. I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
  4. Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.