A Story About Encountering a CreateNetworkInterface Permission Error for VPC Lambda in CDK Express Mode
This page has been translated by machine translation. View original
Introduction
Hello, I'm Junkichi.
I encountered the following error related to Lambda in 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, since CDK automatically attaches AWSLambdaVPCAccessExecutionRole (a managed policy including ENI permissions) to the execution role when vpc is specified in lambda.Function, this permission error should not normally occur.
Conclusion
The cause was that it was running in Express mode. Since Express considers role updates as immediately complete without waiting for policy propagation (eventual consistency), the ENI creation that runs right after results in CreateNetworkInterface being AccessDenied.
The solution is to use standard mode (do not skip stabilization = waiting for propagation).
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, it appears to grant permissions based on whether vpc is configured. I was also able to confirm that the permissions were granted from the template obtained by running synth. This led me to think this is not a CDK issue but rather an IAM data plane eventual consistency issue (propagation delay before an attached role/policy actually takes effect). A similar issue has been reported in the issue tracker (aws-cdk#7998).
Verification
Verification was performed with the following setup.
- aws-cdk-lib
2.261.0/ aws-cdk2.1132.0/ Node.js26.5.0 - Region:
ap-northeast-1
I prepared a CDK stack that allows toggling VPC configuration on and off via a context flag. The following is an excerpt of the Lambda portion.
// VpcConfig is only applied when vpcMode='on'.
// Deploying with vpc=off and then updating to vpc=on reproduces "non-VPC → VPC" conversion.
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 VPC. The same error as the user-reported issue 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 completed without waiting for propagation) |
| 16:02:25 | AWS::Lambda::Function |
UPDATE started |
| 16:02:27 | AWS::Lambda::Function |
UPDATE_FAILED: No CreateNetworkInterface permission (only 4 seconds after role completion, policy not yet propagated) |
In an UPDATE from non-VPC → VPC, "adding VPCAccess to the existing role" and "adding VpcConfig to the function (= ENI creation)" run consecutively within the same update. Since Express considers the role update as immediately complete without waiting for propagation, the ENI creation during the function update a few seconds later is executed against the VPCAccess that has not yet propagated, resulting in AccessDenied.
Trying with Standard Mode
Keeping the same configuration, I ran the same UPDATE changing only the deployment mode to standard. This time it succeeds. The timeline is as follows.
| Time | Resource | Event |
|---|---|---|
| 16:15:34 | AWS::IAM::Role |
UPDATE started |
| 16:15:50 | AWS::IAM::Role |
UPDATE_COMPLETE (stabilization = approximately 16 seconds waiting for propagation) |
| 16:15:52 | AWS::Lambda::Function |
UPDATE started |
| 16:17:57 | AWS::Lambda::Function |
UPDATE_COMPLETE (ENI creation successful, approximately 2 minutes) |
The decisive difference between Express and standard is the time it takes for the role update to complete. Express considers the role update complete in about 1 second, and the ENI creation that ran 4 seconds later collided with the not-yet-propagated policy. Standard, on the other hand, waits about 16 seconds for the role update to stabilize (propagate), so the subsequent ENI creation passes the permission check.
Note: Creation from Scratch Succeeds
As a side note, CREATE from a clean state (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 about 2 minutes. During these approximately 2 minutes, the VPCAccess of the role propagates sufficiently, so the permission passes at the time of ENI creation. In fact, after repeating destroy → create 5 times, the issue 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 of Function creation) |
| Express / fresh CREATE (VPC Lambda) | ✅ Success (even with Express, Lambda::Function alone retains approximately 2 minutes of waiting) |
| standard / UPDATE non-VPC→VPC | ✅ Success (approximately 16 seconds for role update = waiting for propagation) |
| Express / UPDATE non-VPC→VPC | ❌ CreateNetworkInterface error reproduced |
Summary
- When updating a non-VPC Lambda to a VPC Lambda in Express mode,
CreateNetworkInterfaceis executed before IAM propagates, resulting in a permission error. - The workaround is to deploy in standard mode, or to delete the Lambda once and recreate it as a VPC Lambda.
I hope this is helpful to someone.