Why Your Lambda Times Out Inside a VPC (And Why NAT Gateway Is the Fix)
Moving a Lambda function into a VPC is a common requirement for accessing private RDS instances or ElastiCache clusters — but it silently breaks outbound internet access, causing mysterious timeouts when your function tries to reach external APIs. Here is exactly why this happens and how to fix it correctly.
TL;DR
| Scenario | Internet Access? | Why? |
|---|---|---|
| Lambda not in a VPC | ✅ Yes | AWS manages networking; Lambda runs in AWS-owned infrastructure with internet access by default. |
| Lambda in VPC, public subnet | ❌ No | Lambda ENIs do not get a public IP, so the Internet Gateway cannot route return traffic. |
| Lambda in VPC, private subnet, no NAT | ❌ No | No route to the internet exists from the private subnet. |
| Lambda in VPC, private subnet, with NAT Gateway | ✅ Yes | NAT Gateway in public subnet translates private IPs to its own public Elastic IP for outbound traffic. |
The Root Cause: How VPC Networking Actually Works
When Lambda is not attached to a VPC, AWS runs it inside its own managed network infrastructure that already has outbound internet connectivity. The moment you attach Lambda to your VPC, AWS provisions an Elastic Network Interface (ENI) inside your specified subnets. From that point on, Lambda is subject to your VPC's routing rules — nothing more, nothing less.
The critical constraint: Lambda ENIs are never assigned a public IPv4 address, even if you place them in a public subnet. This is a hard platform behavior, not a configuration option. An Internet Gateway (IGW) can only route inbound traffic to resources that have a public IP. Since Lambda's ENI has only a private IP, the IGW has no way to deliver return packets — so outbound connections silently fail or time out.
Analogy: Think of your VPC like a corporate office building. The Internet Gateway is the main lobby door — it only lets people in if they have a registered visitor badge (public IP). Lambda's ENI is an internal employee with no visitor badge. To make a phone call outside the building, the employee must route through the receptionist (NAT Gateway) who has an external line. The outside world only ever sees the receptionist's number, never the employee's internal extension.
Architecture: The Correct Network Flow
- Lambda ENI is provisioned in the private subnet. It holds only a private IP (e.g., 10.0.2.x).
- The private subnet's route table has a default route (
0.0.0.0/0) pointing to the NAT Gateway. - The NAT Gateway lives in the public subnet and holds an Elastic IP (a real public IP).
- The public subnet's route table has a default route (
0.0.0.0/0) pointing to the Internet Gateway. - The Internet Gateway forwards the packet to the external API. Return traffic flows back through the same path in reverse.
Why a Public Subnet Alone Does NOT Work for Lambda
Even if you place Lambda in a public subnet (one with a route to an IGW), the ENI has no public IP. The IGW performs a 1:1 NAT only for resources with an associated public IP or Elastic IP. Lambda ENIs qualify for neither. The packet leaves Lambda's ENI with a private source IP, hits the IGW, and the IGW drops it because it cannot map the private IP to any public address. This is the most common misconception engineers have when first moving Lambda into a VPC.
Step-by-Step: Correct VPC Setup for Lambda Internet Access
Step 1 — VPC and Subnet Layout
You need at minimum: one public subnet (for the NAT Gateway) and one private subnet (for Lambda). They must be in the same VPC.
🔽 CloudFormation: VPC, Subnets, IGW
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: us-east-1a
MapPublicIpOnLaunch: true
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.2.0/24
AvailabilityZone: us-east-1a
InternetGateway:
Type: AWS::EC2::InternetGateway
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref InternetGateway
Step 2 — NAT Gateway with Elastic IP
The NAT Gateway must be deployed in the public subnet. It requires an Elastic IP to represent it to the internet.
🔽 CloudFormation: Elastic IP and NAT Gateway
ElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NATGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt ElasticIP.AllocationId
SubnetId: !Ref PublicSubnet
Step 3 — Route Tables
Two separate route tables are required. The public subnet routes to the IGW. The private subnet routes to the NAT Gateway.
🔽 CloudFormation: Route Tables and Associations
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
PrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGateway
PrivateSubnetAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet
RouteTableId: !Ref PrivateRouteTable
Step 4 — Lambda VPC Configuration
Attach Lambda to the private subnet only. The security group must allow outbound HTTPS (port 443) to reach external APIs.
🔽 CloudFormation: Lambda Function with VPC Config
LambdaSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Lambda outbound internet access
VpcId: !Ref MyVPC
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: my-vpc-lambda
Runtime: python3.12
Handler: index.handler
Role: arn:aws:iam::123456789012:role/MyLambdaExecutionRole
Code:
ZipFile: |
import urllib.request
def handler(event, context):
response = urllib.request.urlopen('https://api.example.com/data')
return {'statusCode': 200, 'body': response.read().decode()}
VpcConfig:
SecurityGroupIds:
- !Ref LambdaSecurityGroup
SubnetIds:
- !Ref PrivateSubnet
Step 5 — IAM: Required Permissions for VPC ENI Management
Lambda's execution role must have permissions to create and manage ENIs. The AWS managed policy AWSLambdaVPCAccessExecutionRole covers this. Attach it to your role following least privilege — do not use AdministratorAccess.
aws iam attach-role-policy \
--role-name MyLambdaExecutionRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
Diagnosing the Problem: Quick Checklist
| Check | What to Verify |
|---|---|
| Subnet type | Lambda must be in a private subnet (no direct IGW route). |
| Private route table | 0.0.0.0/0 must point to the NAT Gateway ID (not IGW). |
| NAT Gateway location | NAT Gateway must be in a public subnet (one with IGW route). |
| NAT Gateway state | Status must be Available in the AWS Console (EC2 → NAT Gateways). |
| Security Group egress | Lambda's SG must allow outbound traffic on the required port (e.g., 443). |
| Elastic IP attached | NAT Gateway must have an Elastic IP allocated and associated. |
Cost Consideration: NAT Gateway Is Not Free
NAT Gateway incurs hourly charges plus per-GB data processing fees. Pricing and exact limits vary — always check the official AWS VPC pricing page. For Lambda functions that only need to reach AWS services (S3, DynamoDB, Secrets Manager, etc.) and not the public internet, consider using VPC Endpoints instead — they eliminate the need for a NAT Gateway for those specific services and are often more cost-effective.
Alternative: VPC Endpoints for AWS Service Access
If your Lambda only calls AWS-native services (not arbitrary public APIs), a Gateway VPC Endpoint (for S3/DynamoDB) or Interface VPC Endpoint (for most other AWS services) routes traffic privately within the AWS network — no NAT Gateway, no internet required.
aws ec2 create-vpc-endpoint \
--vpc-id vpc-0abc123456789def0 \
--service-name com.amazonaws.us-east-1.s3 \
--route-table-ids rtb-0abc123456789def0 \
--vpc-endpoint-type Gateway
Glossary
| Term | Definition |
|---|---|
| ENI (Elastic Network Interface) | A virtual network card provisioned in your VPC subnet. Lambda creates one per availability zone when VPC-attached. |
| NAT Gateway | A managed AWS service that performs Network Address Translation, allowing resources with private IPs to initiate outbound internet connections. |
| Internet Gateway (IGW) | A horizontally scaled VPC component that enables communication between your VPC and the internet. Requires a public IP on the resource for inbound routing. |
| Public Subnet | A subnet whose route table contains a route to an Internet Gateway (0.0.0.0/0 → igw-xxx). |
| VPC Endpoint | A private connection between your VPC and supported AWS services, bypassing the internet entirely. |
Next Steps
- 📖 AWS Docs: Lambda VPC Configuration
- 📖 AWS Docs: NAT Gateways
- 📖 AWS Docs: VPC Endpoints (PrivateLink)
- 🔍 If you only need AWS service access from Lambda, audit whether VPC Endpoints can replace your NAT Gateway entirely — this is a common cost optimization win.
Related Posts
- 📄 NAT Gateway vs NAT Instance: Choosing the Right Outbound Internet Path for Private Subnets
- 📄 Fixing AWS Lambda Timeout: How to Increase It and What the Maximum Limit Is
- 📄 Lambda Connecting to Private RDS: VPC Configuration Explained
- 📄 EC2 No Internet Access in Custom VPC: Attaching an Internet Gateway and Fixing Route Tables
- 📄 Security Group vs. Network ACL: Stateful vs. Stateless Traffic Filtering in AWS VPC
Comments
Post a Comment