A Story About Encountering a CreateNetworkInterface Permission Error for VPC Lambda in CDK Express Mode

A Story About Encountering a CreateNetworkInterface Permission Error for VPC Lambda in CDK Express Mode

When I put Lambda inside a VPC using CDK, I got a CreateNetworkInterface permission error. CDK is supposed to automatically grant the necessary permissions, so I will investigate and narrow down the root cause through testing.
2026.07.21

This page has been translated by machine translation. View original

Introduction

Hello, I'm Junkichi.

I encountered the following error related to Lambda with AWS CDK.

The provided execution role does not have permissions to
call CreateNetworkInterface on EC2 (Lambda, 400)

VPC Lambda needs to create ENIs (Elastic Network Interfaces), so the execution role requires permissions such as ec2:CreateNetworkInterface. However, CDK automatically attaches AWSLambdaVPCAccessExecutionRole (a managed policy containing ENI permissions) to the execution role when vpc is specified in lambda.Function, so this permission error should not normally occur.

Conclusion

The cause was that it was being run in Express mode. Because Express considers role updates as immediately complete without waiting for policy propagation (eventual consistency), the ENI creation that runs immediately after triggers an AccessDenied error for CreateNetworkInterface.

The solution is to deploy in standard mode (without skipping stabilization = propagation waiting).

What is Express Mode

Express mode is a CloudFormation feature that speeds up deployments by skipping stack stabilization and eventual consistency checks. It is also supported in CDK and can be used with the --express flag.

Reference: CloudFormation Express mode

Checking the CDK Implementation

The location in CDK where VPCAccess is granted is here (aws-cdk-lib/aws-lambda/lib/function.ts).

if (props.vpc) {
  // Policy that will have ENI creation permissions
  managedPolicies.push(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole'));
}

As expected, permissions are granted based on whether vpc is configured. The fact that the permissions are being granted could also be confirmed from the template obtained by running synth. This suggests the issue is not with CDK itself, but rather with the eventual consistency of the IAM data plane (propagation delay until a role/policy attachment actually becomes effective). Similar cases have been reported in Issues (aws-cdk#7998).

Verification

Verification was performed with the following setup.

  • aws-cdk-lib 2.261.0 / aws-cdk 2.1132.0 / Node.js 26.5.0
  • Region: ap-northeast-1

For verification, I prepared a CDK stack that can toggle VPC configuration on and off via a context flag. The relevant Lambda excerpt is as follows.

// VpcConfig is only attached when vpcMode='on'.
// By deploying with vpc=off and then updating to vpc=on, we can reproduce a "non-VPC → VPC" update.
const vpcProps =
  vpcMode === 'on'
    ? { vpc, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } }
    : {};
const fn = new lambda.Function(this, 'Fn', {
  runtime: lambda.Runtime.NODEJS_22_X,
  handler: 'index.handler',
  code: lambda.Code.fromInline("exports.handler = async () => ({ statusCode: 200, body: 'ok' });"),
  timeout: Duration.seconds(10),
  ...vpcProps,
});

Reproducing the Issue in Express Mode

Using the same configuration (auto-generated role), I ran an UPDATE in Express mode to convert a non-VPC Lambda to a VPC Lambda. The same error as the user's case was reproduced. The timeline of events is as follows.

Time Resource Event
16:02:23 AWS::IAM::Role UPDATE_COMPLETE — "completed using Express Mode. It may continue becoming available in the background" (VPCAccess addition marked complete without waiting for propagation)
16:02:25 AWS::Lambda::Function UPDATE starts
16:02:27 AWS::Lambda::Function UPDATE_FAILED: No CreateNetworkInterface permission (only 4 seconds after role completion, policy not yet propagated)

In a non-VPC → VPC UPDATE, "adding VPCAccess to the existing role" and "adding VpcConfig to the function (= ENI creation)" run consecutively within the same update. Because Express marks the role update as complete without waiting for propagation, the ENI creation during the function update a few seconds later runs against the not-yet-propagated VPCAccess, resulting in AccessDenied.

Trying with Standard Mode

Keeping the same configuration but switching only the deployment mode to standard, I ran the same UPDATE. This time it succeeded. The timeline is as follows.

Time Resource Event
16:15:34 AWS::IAM::Role UPDATE starts
16:15:50 AWS::IAM::Role UPDATE_COMPLETE (stabilization = approximately 16 seconds waiting for propagation)
16:15:52 AWS::Lambda::Function UPDATE starts
16:17:57 AWS::Lambda::Function UPDATE_COMPLETE (ENI creation succeeded, approximately 2 minutes)

The decisive difference between Express and standard is the time it takes for the role update to complete. Express marks the role update as complete in about 1 second, and the ENI creation that runs 4 seconds later collides with the not-yet-propagated policy. Standard, on the other hand, waits approximately 16 seconds for the role update to stabilize (propagate), so the permissions are in place by the time ENI creation runs.

Note: Creation from Scratch Succeeds

As a side note, a fresh CREATE (VPC Lambda from the start) succeeds even in Express mode.

This is because the creation of AWS::Lambda::Function is not short-circuited even in Express mode and takes approximately 2 minutes. During these approximately 2 minutes, the VPCAccess of the role propagates sufficiently, so the permissions are in place when the ENI is created. In fact, even after repeating destroy→create 5 times, the error never reproduced during CREATE.

Verification Results Summary

The results are summarized as follows.

Configuration Result
standard / fresh CREATE (VPC Lambda) ✅ Success (propagation absorbed by approximately 2 minutes for Function creation)
Express / fresh CREATE (VPC Lambda) ✅ Success (even in Express, approximately 2-minute wait remains for Lambda::Function only)
standard / UPDATE non-VPC→VPC ✅ Success (role update takes approximately 16 seconds = propagation wait)
Express / UPDATE non-VPC→VPC ❌ CreateNetworkInterface error reproduced

Summary

  • When updating a non-VPC Lambda to a VPC Lambda in Express mode, CreateNetworkInterface is executed before IAM propagates, resulting in a permission error.
  • The workaround is to deploy in standard mode, or to delete the Lambda once and then recreate it as a VPC Lambda.

I hope this is helpful to someone.

Share this article

AWSのお困り事はクラスメソッドへ