Set up IPv6 VPC for Lambda to access public internet without NATGateway and public IPv4 address
Background
I created an AWS Lambda behind the AWS ApiGateway, it also connects an RDS instance which is placed in a private subnet. The Lambda needs to call an external server (AppStore Server). I followed some docs and created an NATGateway for testing, until I saw the charge of the NATGateway on the AWS bill in a few days.
Options
After digging into the case in these days, I have several potential ways to connect AWS Lambda to the public internet with charge or no charge at all.
About the NATGateway pricing and Public IPv4 pricing:
- NATGateway: You have to pay at least ~$30/month even no data processing and transfer.
- Public IPv4 (including Elastic IPv4): New charge takes effect on February 1, 2024. $0.005/hour per 1 ip for in-use or idle.
(Both of them are available on: https://aws.amazon.com/vpc/pricing/)
Decision
Based on the Principle
- Security: Protect user’s data, also protect my infrastructures
- Cost: As cheap as possible during the startup phase.
Result
Now I run the Lambda within a dual stack (both IPv4 and IPv6) VPC. The infra was built by CDK. Lambda is connecting to public internet with an IPv6 address and to the RDS in the private VPC. No public IPv4 address at all.
Implementation
There are ton of the blogs/articles on the internet to show the process for setting up Lambda + NATGateway/NATInstance. So I won’t copy them again.
Next, I’ll show how to set up the Lambda into a dual stack VPC including the RDS, with no public IPv4.
Overall Infrastructure
Code
All the Typescript code is based on the "aws-cdk-lib": "^2.122.0",
(released on 2024-01-18, as of 2024-01-21). I read a bunch of the AwsCDK GitHub issues, they released
a few change related to the IPv6 recently, so use the latest version.
My understanding, even the latest CDK lib, not fully support the CDK L3 constructs/api, have to use the CloudFormation L1 constructs to enable the features.
Create Network
Have listed the network config on the Overall Infra diagram.
Three types of the subnets:
-
PRIVATE_WITH_EGRESS
orService
is a private subnet with an egress-only internet gateway (EIGW), can connect to the Internet, but will not allow connections to be initiated from the Internet. -
PRIVATE_ISOLATED
orDB
is an absolutely private subnet, only can be accessed within VPC. -
PUBLIC
orPublic
can access the internet via internet gateway, I’ll place an EC2 instance as bastion host later.
The key points are explained in code.
Note: you may see the examples to create route table for IPv6 on other articles. This is not needed as it is built into CDK for Dual-Stack-VPC in new release.
Create Lambda
Use the CloudFormation L1 constructs to enable the IPv6 flag.
The Lambda function API for VpcConfig: https://docs.aws.amazon.com/lambda/latest/dg/API_VpcConfig.html#SSS-Type-VpcConfig-Ipv6AllowedForDualStack
You also can find the IPv6 flag on Lambda console under “Configuration”->“VPC”->“Subnets”->“Allow IPv6 traffic”
Create RDS Instance
Enable the dual network flag, easy change:
Create Bastion Host
Only AWS Nitro System is able to support ipv6-only subnet, so choose the correct instance.
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html#ec2-nitro-instances
The instance also can be used as a NATInstance which has the similar functions like NATGateway or Egress-Only-Internet Gateway. (A lot of articles to guide the setup for NATInstance)
Reference
Enabling IPv6 on Resources and VPCs: https://github.com/aws/aws-cdk/issues/894
Fun Fact
Right now, the Lambda can access the public internet with IPv6 address, however, I can’t shoot the goal of calling AppStore Server from the Lambda.
Why?
Guess it :)
Updates
Created on 2024-01-21
Update on 2024-02-08: add bastion host part
Update on 2024-05-28: update ipv6AllowedForDualStack
to lambda stack, based on awscdk latest release