Lambda VPC — Accessing Resources in a Virtual Private Cloud
In this tutorial, you will learn about Lambda VPC. We cover key concepts, practical examples, and best practices to help you master this topic.
AWS Lambda functions can access resources inside a Virtual Private Cloud (VPC) by attaching to VPC subnets and security groups, enabling secure connections to RDS, ElastiCache, and internal services.
What You'll Learn
By the end of this lesson you will understand how to configure Lambda for VPC access, connect to RDS databases and ElastiCache, manage VPC cold starts, and use VPC endpoints for AWS services.
Why It Matters
Many production serverless applications need access to database services like RDS, caching services like ElastiCache, or internal APIs running on EC2. Without VPC configuration, Lambda cannot reach these private resources.
Real-World Use
DodaTech's analytics platform uses Lambda functions in a VPC to query an RDS PostgreSQL database for historical data and cache results in ElastiCache Redis. The VPC configuration keeps all data traffic within the private network.
flowchart TD
L[AWS Lambda VPC] --> S[VPC Subnet]
S --> RDS[RDS Database]
S --> EC[ElastiCache Redis]
S --> I[Internal API on EC2]
L --> E[VPC Endpoint]
E --> SSM[SSM Parameter Store]
style L fill:#f90,color:#fff
Configuring VPC Access
Lambda VPC configuration requires specifying one or more subnets and security groups. Lambda creates an elastic network interface (ENI) in each subnet.
# vpc_config.py
# Understanding Lambda VPC configuration
class VPCConfig:
def __init__(self, subnet_ids, security_group_ids):
self.subnets = subnet_ids
self.security_groups = security_group_ids
def describe(self):
print("Lambda VPC Configuration:")
print(f" Subnets: {', '.join(self.subnets)}")
print(f" Security Groups: {', '.join(self.security_groups)}")
print(f" ENIs Created: {len(self.subnets)} (one per subnet)")
print(" Route Table: Routes traffic within VPC")
vpc = VPCConfig(
subnet_ids=["subnet-abc123", "subnet-def456", "subnet-ghi789"],
security_group_ids=["sg-db-access"]
)
vpc.describe()
Expected output:
Lambda VPC Configuration:
Subnets: subnet-abc123, subnet-def456, subnet-ghi789
Security Groups: sg-db-access
ENIs Created: 3 (one per subnet)
Route Table: Routes traffic within VPC
Connecting to RDS
Lambda can connect to RDS using standard database drivers. The security group must allow inbound connections from Lambda on the database port.
# rds_connection.py
# Connecting to RDS from Lambda
import json
import os
def lambda_handler(event, context):
db_host = os.environ.get("DB_HOST", "my-db.cluster-abc123.us-east-1.rds.amazonaws.com")
db_port = os.environ.get("DB_PORT", "5432")
db_name = os.environ.get("DB_NAME", "appdb")
db_user = os.environ.get("DB_USER", "app_user")
print(f"Connecting to PostgreSQL at {db_host}:{db_port}/{db_name}")
print(f"Authenticating as {db_user}")
conn = connect_with_pool(db_host, db_port, db_name, db_user)
result = query_users(conn)
return {"statusCode": 200, "body": json.dumps({"users": result})}
def connect_with_pool(host, port, db_name, user):
print(" Creating connection pool (reused across warm starts)")
return {"connected": True, "host": host, "total_connections": 5}
def query_users(conn):
print(" Executing: SELECT id, name, email FROM users LIMIT 10")
return [
{"id": 1, "name": "Alice", "email": "alice@example.com"},
{"id": 2, "name": "Bob", "email": "bob@example.com"}
]
print(lambda_handler({}, None)["body"])
Expected output:
Connecting to PostgreSQL at my-db...rds.amazonaws.com:5432/appdb
Authenticating as app_user
Creating connection pool (reused across warm starts)
Executing: SELECT id, name, email FROM users LIMIT 10
[{"id": 1, "name": "Alice", "email": "alice@example.com"}, {"id": 2, "name": "Bob", "email": "bob@example.com"}]
VPC Cold Start Impact
VPC-configured Lambda functions have additional cold start latency because Lambda must create and attach an elastic network interface.
# vpc_cold_start.py
# VPC cold start measurement
import time
def measure_vpc_cold_start():
start = time.time()
print("[VPC Cold Start] Requesting ENI allocation...")
time.sleep(1.0)
print("[VPC Cold Start] Attaching ENI to Lambda...")
time.sleep(0.5)
print("[VPC Cold Start] Configuring routing...")
time.sleep(0.3)
print("[VPC Cold Start] Initializing runtime...")
time.sleep(0.2)
elapsed = (time.time() - start) * 1000
return elapsed
def measure_no_vpc_cold_start():
start = time.time()
print("[No VPC Cold Start] Initializing runtime...")
time.sleep(0.2)
elapsed = (time.time() - start) * 1000
return elapsed
vpc = measure_vpc_cold_start()
no_vpc = measure_no_vpc_cold_start()
print(f"\nVPC cold start: {vpc:.0f}ms")
print(f"No VPC cold start: {no_vpc:.0f}ms")
print(f"VPC overhead: {vpc - no_vpc:.0f}ms")
Expected output:
[VPC Cold Start] Requesting ENI allocation...
[VPC Cold Start] Attaching ENI to Lambda...
[VPC Cold Start] Configuring routing...
[VPC Cold Start] Initializing runtime...
VPC cold start: 2000ms
No VPC cold start: 200ms
VPC overhead: 1800ms
VPC Endpoints
Use VPC endpoints to access AWS services (S3, DynamoDB, SQS) without traversing the public internet.
# vpc_endpoints.py
# VPC endpoints for AWS services
def describe_vpc_endpoints():
endpoints = {
"s3": {
"type": "Gateway",
"service": "com.amazonaws.us-east-1.s3",
"benefit": "Private access to S3 without NAT gateway"
},
"dynamodb": {
"type": "Gateway",
"service": "com.amazonaws.us-east-1.dynamodb",
"benefit": "Private access to DynamoDB"
},
"sqs": {
"type": "Interface",
"service": "com.amazonaws.us-east-1.sqs",
"benefit": "Private access to SQS"
},
"secretsmanager": {
"type": "Interface",
"service": "com.amazonaws.us-east-1.secretsmanager",
"benefit": "Private access to Secrets Manager"
}
}
for name, config in endpoints.items():
print(f"{name:15s} {config['type']:10s} -> {config['benefit']}")
describe_vpc_endpoints()
Common Mistakes
Not having a NAT gateway for internet access: Lambda in a private subnet needs a NAT gateway to access the internet. Without it, external API calls fail.
Creating too many subnets: Each subnet creates an ENI. More subnets increase ENI creation time and cold start latency. Use 2-3 subnets in different AZs.
Using VPC when not needed: If your Lambda only accesses DynamoDB and S3, use VPC endpoints instead of putting Lambda in a VPC.
Security group too restrictive: The security group must allow outbound connections to RDS. Without egress rules, connections time out.
Forgetting RDS proxy for connection pooling: Lambda scale creates many database connections. Use RDS Proxy to manage connection pooling.
Practice Questions
Why does VPC configuration increase cold start latency? Lambda must create and attach an elastic network interface to the execution environment before invocation.
How does Lambda access the internet from a VPC? The function must be in a private subnet with a route to a NAT gateway, or use a public subnet.
What is RDS Proxy and why use it with Lambda? RDS Proxy manages database connection pooling, preventing Lambda from exhausting database connections during scaling.
How many subnets should you configure for Lambda VPC? 2-3 subnets across different Availability Zones for high availability.
Challenge: Design a VPC architecture for Lambda functions that need access to RDS, ElastiCache, and S3 (via VPC endpoint) without internet access.
FAQ
Mini Project
Create a Lambda function in a VPC that connects to RDS PostgreSQL, queries a users table, caches the result in ElastiCache Redis, and returns the data. Include connection pooling with RDS Proxy.
import json
def lambda_handler(event, context):
db_host = "database.cluster-abc.us-east-1.rds.amazonaws.com"
cache_host = "redis-cluster.abc.0001.use1.cache.amazonaws.com"
print(f"Checking cache at {cache_host}")
cached = None
if cached:
print("Cache HIT - returning cached data")
return {"statusCode": 200, "body": cached}
print("Cache MISS - querying database")
print(f"Connecting to RDS Proxy at {db_host}")
data = query_users()
print("Storing result in cache")
return {"statusCode": 200, "body": json.dumps(data)}
def query_users():
return [{"id": 1, "name": "Alice", "email": "alice@example.com"}]
print(lambda_handler({}, None)["body"])
What's Next
Next: Lambda Monitoring (CloudWatch) for Observability.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro