---
cuppy_hub: aws
cuppy_path: patterns/lambda-in-vpc.md
cuppy_section: docs
cuppy_doc: WR7Y-0CMK
cuppy_doc_uuid: ee721601-3f13-4b40-b5a6-86bbdf4cae3e
cuppy_permalink: https://cuppy.io/aws/d/WR7Y-0CMK
cuppy_version: 4
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/aws/docs/patterns/lambda-in-vpc
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: cf3b11c35f68146dc729dd3f421acce9842a1e883a656adc1fabd4cf77342674
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Lambda in a VPC

**Only attach a function to a VPC if it must reach private resources, such as a database, an internal service or a private endpoint.** Once it is attached, the function has no internet access and **no public IP, even in a public subnet**. Every call to an AWS API or the internet needs a NAT gateway or a VPC endpoint. Without one, the call hangs until `Task timed out`.

## What crosses the handoff

| Side | Provides / expects |
|---|---|
| **Lambda** | Creates network interfaces in the subnets you list, using the **execution role**. That needs the `ec2:CreateNetworkInterface`/`Describe…`/`Delete…` permissions in `AWSLambdaVPCAccessExecutionRole`. The role grants the *right to create interfaces*, not any network path. |
| **VPC** | Subnets with free IP addresses, security groups that allow the function's outbound traffic, and routes: private subnets → NAT gateway (a zonal one in a public subnet, or a regional one that needs no public subnet) → internet gateway, and/or VPC endpoints for the AWS services the function calls. |

## Known-good

1. Two or more **private** subnets in different Availability Zones, each with a route `0.0.0.0/0 → nat-…`. A zonal NAT gateway sits in a public subnet whose route goes to the internet gateway; a regional NAT gateway (`create-nat-gateway --vpc-id … --availability-mode regional`) needs no public subnet and serves every AZ with one ID (`reference/vpc/routing-and-gateways.md`).
2. A security group for the function with outbound HTTPS, plus whatever the database needs. Allow inbound on the **database's** group from the function's group.
3. The execution role has `AWSLambdaVPCAccessExecutionRole` (or equivalent) **and** the function's own permissions.
4. Attach:

```
aws lambda update-function-configuration --function-name <fn> \
  --vpc-config SubnetIds=<subnet-a>,<subnet-b>,SecurityGroupIds=<sg>
aws lambda wait function-updated-v2 --function-name <fn>
```

5. Optional, to avoid NAT for AWS traffic: VPC endpoints (gateway endpoints for S3 and DynamoDB; interface endpoints for others such as `secretsmanager`, `sqs`, `sts`) with private DNS on. Their security groups must allow 443 from the function's group. Endpoint policies are a second policy layer (`patterns/iam-to-vpc-endpoints.md`).

## Known-bad

| Configuration | Symptom |
|---|---|
| Function in a **public** subnet, expecting internet | `Task timed out after N seconds` on the first outbound call: Lambda never gets a public IP |
| Private subnets with no NAT route and no endpoint for the service | Same timeout. No error from the SDK unless its own timeout is shorter |
| Gateway endpoint for S3 created but not associated with the function's route tables | S3 calls time out; other calls work |
| Interface endpoint without private DNS | The SDK resolves the public name and times out |
| Execution role without the ENI permissions | Update or invoke fails with `EC2AccessDeniedException` (502); the function's state shows the reason |
| Subnets nearly full | `SubnetIPAddressLimitReachedException` (502) on invoke or scale-out |
| Many functions or subnets × security group combinations | `ENILimitReachedException` (502): the per-VPC Lambda network-interface quota is reached |
| A subnet or security group deleted after configuration | `InvalidSubnetIDException` / `InvalidSecurityGroupIDException` (502) |
| Security group allows no outbound traffic | Timeouts on every connection |

## Which side is wrong?

- **Timeout with no error** → the network side: routes, NAT, endpoints, security group egress. Reachability Analyzer from the function's network interface names the blocking layer (`guides/vpc/diagnose-connection-timeout.md`). Check what the function calls, then `aws ec2 describe-route-tables --filters Name=association.subnet-id,Values=<subnet>`.
- **A 502 exception naming EC2, ENI or subnets** → the Lambda side's set-up: the execution role, subnet IP capacity or quotas (`reference/lambda/errors.md`).
- **The connection is refused by the database** → the database's security group does not allow the function's group.

## Design notes

- Make SDK client timeouts shorter than the function timeout, so a missing route produces an error message rather than a bare `Task timed out`.
- Updating VPC settings puts the function into a `Pending` update. Wait before invoking (`ResourceConflictException` otherwise).
- To detach, use `--vpc-config SubnetIds=[],SecurityGroupIds=[]`.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 131 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/aws/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
