CDK Expressモードで VPC Lambda の CreateNetworkInterface 権限エラーに遭遇した話
はじめに
こんにちは、じゅんきちです。
AWS CDK でLambdaに関する以下のエラーに遭遇しました。
The provided execution role does not have permissions to
call CreateNetworkInterface on EC2 (Lambda, 400)
VPC Lambda は ENI(Elastic Network Interface)を作成するため、実行ロールに ec2:CreateNetworkInterface などの権限が必要です。しかし CDK は lambda.Function に vpc を指定すると AWSLambdaVPCAccessExecutionRole(ENI 権限を含むマネージドポリシー)を実行ロールへ自動付与するため、本来この権限エラーは起きないはずです。
結論
Express モードで実行していたことが原因でした。Express はポリシー伝播(eventual consistency)を待たずにロール更新を即完了扱いにするため、その直後に走る ENI 作成で CreateNetworkInterface が AccessDenied になります。
解決策は standard モードで行う(安定化=伝播待ちを飛ばさない)ことです。
Expressモードとは
Express モードは、CloudFormationの機能でスタックの安定化(stabilization)や eventual consistency のチェックを省略してデプロイを高速化するモードです。CDKでも対応しており--express フラグで利用します。
参考: CloudFormation Express mode
CDKの実装を確認する
CDK 内部で VPCAccess を付与している箇所はここです(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'));
}
当然ながらvpcの設定有無で権限を付与してそうです。権限が付与されていることはsynthをして得られたテンプレートからも確認できました。となるとこれはcdkの問題ではなくIAM データプレーンの eventual consistency(ロール/ポリシーのアタッチが実際に有効になるまでの伝播遅延)かなと考えられます。Issueにも似たような事象が報告されていました(aws-cdk#7998)。
検証
検証は以下で行いました。
- aws-cdk-lib
2.261.0/ aws-cdk2.1132.0/ Node.js26.5.0 - リージョン:
ap-northeast-1
検証用に、VPC 化の有無を context フラグで切り替えられる CDK スタックを用意しました。Lambda 部分の抜粋は次の通りです。
// vpcMode='on' のときだけ VpcConfig を付与。
// vpc=off でデプロイ後に vpc=on へ UPDATE すると「非VPC → VPC 化」を再現できる。
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,
});
Express モードで事象を再現する
同一構成(role 自動生成)で、非VPC Lambda を VPC 化する UPDATE を Express で実行しました。ユーザー事象と同一のエラーが再現しました。イベントの時系列は以下の通りです。
| 時刻 | リソース | イベント |
|---|---|---|
| 16:02:23 | AWS::IAM::Role |
UPDATE_COMPLETE —「completed using Express Mode. It may continue becoming available in the background」(VPCAccess 追加を伝播待ちせず完了扱い) |
| 16:02:25 | AWS::Lambda::Function |
UPDATE 開始 |
| 16:02:27 | AWS::Lambda::Function |
UPDATE_FAILED: CreateNetworkInterface 権限なし(ロール完了のわずか4秒後、ポリシー未伝播) |
非VPC → VPC 化の UPDATE では、「既存ロールへ VPCAccess を追加」と「関数へ VpcConfig を追加(=ENI 作成)」が同一更新の中で連続して走ります。Express はロール更新を伝播待ちせず即完了にするため、その数秒後の関数更新の ENI 作成が、まだ伝播していない VPCAccess に対して実行され AccessDenied になります。
standardモードでやってみる
構成はそのままに、デプロイモードだけを standard に変えて同じ UPDATE を実行しました。今度は成功します。時系列は以下の通りです。
| 時刻 | リソース | イベント |
|---|---|---|
| 16:15:34 | AWS::IAM::Role |
UPDATE 開始 |
| 16:15:50 | AWS::IAM::Role |
UPDATE_COMPLETE(安定化=伝播待ちに約16秒) |
| 16:15:52 | AWS::Lambda::Function |
UPDATE 開始 |
| 16:17:57 | AWS::Lambda::Function |
UPDATE_COMPLETE(ENI 作成成功、約2分) |
Express と standard で決定的に違うのは、ロール更新の完了までにかかる時間です。Express はロール更新を約1秒で完了扱いにし、その4秒後に走った ENI 作成が未伝播のポリシーに衝突しました。一方 standard はロール更新の安定化(伝播)に約16秒かけて待つため、その後の ENI 作成では権限が通ります。
補足:更新ではなく作成は通る
補足として、まっさらな状態からの CREATE(最初から VPC Lambda)は Express でも成功します。
AWS::Lambda::Function の作成は Express でも短絡されず、約2分かかるためです。この約2分の間にロールの VPCAccess が十分に伝播するので、ENI 作成時には権限が通ります。実際destroy→create を5回繰り返しても、CREATE では一度も再現しませんでした。
検証結果まとめ
まとめると次の通りです。
| 構成 | 結果 |
|---|---|
| standard / fresh CREATE(VPC Lambda) | ✅ 成功(Function 作成の約2分で伝播を吸収) |
| Express / fresh CREATE(VPC Lambda) | ✅ 成功(Express でも Lambda::Function だけは約2分待機が残る) |
| standard / UPDATE 非VPC→VPC | ✅ 成功(ロール更新に約16秒=伝播待ち) |
| Express / UPDATE 非VPC→VPC | ❌ CreateNetworkInterface エラー再現 |
まとめ
- Expressモードで非VPC Lambda を VPC Lambdaへ更新すると IAMが伝播する前に、
CreateNetworkInterfaceが実行され権限エラーが出る。 - 対策は standard モードでデプロイをするか、一度Lambdaを削除した後にVPC Lambdaとして再作成すること
どなたかの参考になれば幸いです。




