skip to content

What actually changes for an AWS Lambda function when you attach it to a VPC, and what network resources does Lambda create to make that work?

level: middleimportance: should knowfreq 58%

answer

  1. you supply subnets and security groups
  2. traffic rides interfaces in your subnets
  3. private addresses only, never public
  4. shared, not one per concurrent execution
  5. execution role needs EC2 interface actions

basics

~20 s

Attaching a function to subnets and security groups makes Lambda place its traffic on elastic network interfaces inside your VPC. The function then has private IPs only, obeys your security groups and route tables, and loses default internet access.

solid answer

~50 s

You attach a function by giving it a `VpcConfig` — a set of subnet IDs and security group IDs. Lambda then creates Hyperplane elastic network interfaces in those subnets and routes the function's outbound traffic through them, so the function behaves like anything else in the VPC: your security group governs its egress, the subnet route table decides where packets go, and it resolves names through the VPC resolver, including private hosted zones. Two things change that surprise people. First, the function now has only private IPs and can never get a public one, so reaching the internet needs a route to a NAT gateway or a VPC endpoint. Second, the execution role must allow `ec2:CreateNetworkInterface`, `ec2:DescribeNetworkInterfaces` and `ec2:DeleteNetworkInterface` — the managed `AWSLambdaVPCAccessExecutionRole` policy covers it. The interfaces are shared across execution environments and across functions with identical VPC config, not created per concurrent invocation.

code

bash · 7 lines
bash
aws lambda update-function-configuration \
  --function-name order-writer \
  --vpc-config 'SubnetIds=subnet-0a1b2c3d,subnet-0e4f5a6b,SecurityGroupIds=sg-07c8d9e0'

aws lambda get-function-configuration \
  --function-name order-writer \
  --query 'VpcConfig'

go deeper

for a junior

Know that VPC attachment means supplying subnets and security groups, and that its purpose is reaching private resources such as an RDS database. Say plainly that the function then has no public address.

for a middle

Explain the mechanics — Lambda provisions shared network interfaces in your subnets when the configuration changes, the security group and route table now govern traffic, and the execution role needs the EC2 interface permissions.

for a senior

Demonstrate operational judgment: size and spread subnets so address exhaustion cannot throttle scaling, plan the egress path before attaching, and enforce database access by referencing the function's security group.

for a principal

Own the policy question — which classes of workload are allowed inside the VPC at all, how the network path is standardised across accounts, and what the blast radius and cost of that choice is versus keeping functions outside.

## What VPC attachment is for By default a Lambda function runs in AWS-managed network space, with outbound internet access and reachability to public AWS service endpoints. That is the right default for most functions. You attach a function to a VPC for exactly one reason: it needs to reach something that has only a private address — an RDS instance, an ElastiCache cluster, an internal load balancer, a service on-premises across a VPN or Direct Connect. Attaching for any other reason buys you constraints with no benefit. ## The configuration Attachment is a function-level setting: a `VpcConfig` containing subnet IDs and security group IDs. ```bash aws lambda update-function-configuration \ --function-name order-writer \ --vpc-config 'SubnetIds=subnet-0a1b,subnet-0c2d,SecurityGroupIds=sg-0e3f' ``` Give it private subnets in at least two Availability Zones. If one AZ becomes impaired, or one subnet runs out of addresses, Lambda can still place traffic through the others. A single-subnet function is a single-AZ function. ## The network interfaces Lambda does not run your code inside your VPC in the way an EC2 instance sits inside it. Instead it creates elastic network interfaces in your subnets and connects execution environments to them through AWS's Hyperplane layer, a shared NAT-style fabric. Two consequences follow, and both are commonly asked: - **The interfaces are shared.** One ENI is not one concurrent execution. Lambda creates interfaces per unique combination of subnet and security group set, and many execution environments — including environments of *different* functions in the same account that happen to have the same VPC configuration — multiplex over them. The number scales with throughput, but far more slowly than concurrency does. - **They are created at configuration time.** The interfaces are provisioned when you create or update the function's VPC configuration, not on the invocation path. That is why a `update-function-configuration` call that changes VPC settings takes a while to reach an active state, and why scaling up no longer waits on interface creation. Because interfaces are real ENIs in your subnets, they consume private IP addresses from those subnets. A function that scales hard against a /28 subnet shared with other workloads can exhaust the pool, and the symptom is invocation failures rather than a slow function. Sizing the subnets for the peak, and keeping Lambda's subnets separate from instance subnets, is the practical mitigation. ## What behaves differently afterwards **Egress is now yours to route.** The function's interfaces have private addresses only. You cannot assign a public IP or an Elastic IP to them. Anything on the public internet — a third-party payment API, a webhook, a package registry — is reachable only if the subnet's route table sends `0.0.0.0/0` to a NAT gateway sitting in a public subnet. Public AWS service endpoints count as "the internet" for this purpose, so a VPC-attached function calling S3, Secrets Manager or DynamoDB needs either that NAT route or a VPC endpoint for the service. **Security groups apply.** The security group you attach governs the function's traffic. Because security groups are stateful, egress-only rules are usually enough on the Lambda side; the more common mistake is on the other end — the RDS instance's security group must allow inbound on the database port *from the Lambda security group*, which is how you express "only my function may connect". **DNS changes.** The function resolves through the VPC's Route 53 Resolver, so private hosted zones, VPC endpoint private DNS names, and resolver rules for on-premises zones all start working. This is often the actual reason a name resolves differently before and after attachment. **The execution role needs more.** Lambda manages the interfaces using your execution role's credentials, so it needs `ec2:CreateNetworkInterface`, `ec2:DescribeNetworkInterfaces` and `ec2:DeleteNetworkInterface`. Attach `AWSLambdaVPCAccessExecutionRole` — which also carries the basic CloudWatch Logs permissions — rather than hand-writing them. Without those permissions the function will not transition to an active state after you set the VPC config, and the error points at EC2, not at Lambda, which throws people off. ## The judgment an interviewer is listening for Attach only when a private resource requires it; keep the rest of the fleet outside the VPC. When you do attach, use multiple private subnets, size them for peak address consumption, plan the egress path deliberately, and remember that the security-group relationship with the database is the thing that actually enforces least privilege on the network path.

  • Does each concurrent execution get its own network interface?
    No. Lambda creates interfaces per unique subnet and security-group combination and multiplexes execution environments over them through the Hyperplane fabric — including environments of other functions in the account with identical VPC configuration. Interface count grows with sustained throughput, not one-for-one with concurrency, and the interfaces are provisioned when you change the VPC configuration rather than on the invocation path.
  • Why put the function in two or more subnets in different Availability Zones?
    Resilience and address capacity. If a single subnet's AZ is impaired, or that subnet runs out of free private addresses, a function configured with only that subnet has nowhere to place traffic. Listing private subnets in several AZs lets Lambda keep working through the others. It also spreads address consumption when the function scales hard.
  • How do you restrict which VPC resources a Lambda function can reach?
    With the security group attached to its VPC configuration and the subnets' route tables. The strongest common pattern is referencing the Lambda security group as the source in the database's inbound rule, so only functions carrying that group can open a connection — an identity-shaped rule rather than a CIDR range that drifts as the network changes.

saying these in an interview costs you the question

  • Says every concurrent execution creates its own network interface
  • Thinks a public subnet gives a VPC-attached function internet access
  • Forgets the execution role needs EC2 network-interface permissions
  • Attaches a function to a VPC just to call S3 or DynamoDB
  • Ignores subnet address capacity when the function scales

context