Amazon EventBridge Scheduler を AWS CDK で構成する際に “Resolution error: All principals in a PolicyStatement must have the same Conditions” というエラーが発生する場合の対処
こんにちは、CX 事業本部/製造ビジネステクノロジー部/新規サービスチームの若槻です。
Amazon EventBridge Scheduler は、Lambda 関数などのターゲットをスケジュール実行できる Amazon EventBridge の機能です。
以前までは EventBridge スケジュールルールでも同様のことができましたが、EventBridge Scheduler はスケジュール実行のための機能として特化しており、スケジュールルールに比べて高度なカスタマイズ性やスケーラビリティを備えています。両者の比較は次の記事が参考になります。
そして EventBridge Scheduler を AWS CDK で構成する場合は現状では alpha module を利用します。
この AWS CDK の alpha module を利用して Amazon EventBridge Scheduler を構成する際に、 Resolution error: All principals in a PolicyStatement must have the same Conditions
というエラーが発生したので対処した内容を共有します。
はじめに結論
EventBridge Scheduler では次のように aws_scheduler_targets_alpha.LambdaInvoke
を使用して Lambda 関数を実行ターゲットとして指定するのですが、その際に 同一の CDK スタック内で複数の Scheduler を作成する場合 は、ターゲットで明示的に role
プロパティを指定する必要がありました。
import { aws_lambda_nodejs, aws_lambda, aws_iam, Stack, TimeZone, } from 'aws-cdk-lib'; import * as aws_scheduler_alpha from '@aws-cdk/aws-scheduler-alpha'; import * as aws_scheduler_targets_alpha from '@aws-cdk/aws-scheduler-targets-alpha'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id); const accounId = this.account; const region = this.region; // Lambda 関数 const helloFunc = new aws_lambda_nodejs.NodejsFunction(this, 'HelloFunc', { runtime: aws_lambda.Runtime.NODEJS_20_X, architecture: aws_lambda.Architecture.ARM_64, }); // Lambda 実行ターゲット const target = new aws_scheduler_targets_alpha.LambdaInvoke(helloFunc, { role: new aws_iam.Role(this, 'Role', { assumedBy: new aws_iam.ServicePrincipal( 'scheduler.amazonaws.com' ).withConditions({ StringEquals: { 'aws:SourceAccount': accounId, }, StringLike: { 'aws:SourceArn': `arn:aws:scheduler:${region}:${accounId}:schedule/default/*`, }, }), }), }); // Scheduler その1 new aws_scheduler_alpha.Schedule(this, 'Shedule1', { schedule: aws_scheduler_alpha.ScheduleExpression.cron({ minute: '0', hour: '1', month: '3', day: '1-31', year: '2024', timeZone: TimeZone.ASIA_TOKYO, }), target, }); // Scheduler その2 new aws_scheduler_alpha.Schedule(this, 'Shedule2', { schedule: aws_scheduler_alpha.ScheduleExpression.cron({ minute: '0', hour: '1', month: '4', day: '1-10', year: '2024', timeZone: TimeZone.ASIA_TOKYO, }), target, }); } }
CDK デプロイにより、上記で定義した 2 つの Scheduler が作成されました。
事象
当初、同じ Lambda 関数をターゲットとした複数の Scheduler を次のように作成しようとしました。
import { aws_lambda_nodejs, aws_lambda, Stack, TimeZone } from 'aws-cdk-lib'; import * as aws_scheduler_alpha from '@aws-cdk/aws-scheduler-alpha'; import * as aws_scheduler_targets_alpha from '@aws-cdk/aws-scheduler-targets-alpha'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id); // Lambda 関数 const helloFunc = new aws_lambda_nodejs.NodejsFunction(this, 'HelloFunc', { runtime: aws_lambda.Runtime.NODEJS_20_X, architecture: aws_lambda.Architecture.ARM_64, }); // Lambda 実行ターゲット const target = new aws_scheduler_targets_alpha.LambdaInvoke(helloFunc, {}); // Scheduler その1 new aws_scheduler_alpha.Schedule(this, 'Shedule1', { schedule: aws_scheduler_alpha.ScheduleExpression.cron({ minute: '0', hour: '1', month: '3', day: '1-31', year: '2024', timeZone: TimeZone.ASIA_TOKYO, }), target, }); // Scheduler その2 new aws_scheduler_alpha.Schedule(this, 'Shedule2', { schedule: aws_scheduler_alpha.ScheduleExpression.cron({ minute: '0', hour: '1', month: '4', day: '1-10', year: '2024', timeZone: TimeZone.ASIA_TOKYO, }), target, }); } }
しかし CDK Synth 時に次のようなエラーが発生しました。
$ cdk synth Error: Resolution error: Resolution error: Resolution error: All principals in a PolicyStatement must have the same Conditions (got '{}' and '{"StringEquals":{"aws:SourceAccount":"${Token[AWS.AccountId.9]}"}}'). Use multiple statements instead..
切り分け
その1
実行対象の Lambda 関数およびターゲットを Scheduler ごとに分けてみました。
import { aws_lambda_nodejs, aws_lambda, Stack, TimeZone } from 'aws-cdk-lib'; import * as aws_scheduler_alpha from '@aws-cdk/aws-scheduler-alpha'; import * as aws_scheduler_targets_alpha from '@aws-cdk/aws-scheduler-targets-alpha'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id); // Lambda 関数1 const helloFunc = new aws_lambda_nodejs.NodejsFunction(this, 'HelloFunc', { runtime: aws_lambda.Runtime.NODEJS_20_X, architecture: aws_lambda.Architecture.ARM_64, }); // Lambda 実行ターゲット1 const target = new aws_scheduler_targets_alpha.LambdaInvoke(helloFunc, {}); // Scheduler その1 new aws_scheduler_alpha.Schedule(this, 'Shedule1', { schedule: aws_scheduler_alpha.ScheduleExpression.cron({ minute: '0', hour: '1', month: '3', day: '1-31', year: '2024', timeZone: TimeZone.ASIA_TOKYO, }), target, }); // Lambda 関数2 const helloFunc2 = new aws_lambda_nodejs.NodejsFunction( this, 'HelloFunc2', { runtime: aws_lambda.Runtime.NODEJS_20_X, architecture: aws_lambda.Architecture.ARM_64, } ); // Lambda 実行ターゲット2 const target2 = new aws_scheduler_targets_alpha.LambdaInvoke( helloFunc2, {} ); // Scheduler その2 new aws_scheduler_alpha.Schedule(this, 'Shedule2', { schedule: aws_scheduler_alpha.ScheduleExpression.cron({ minute: '0', hour: '1', month: '4', day: '1-10', year: '2024', timeZone: TimeZone.ASIA_TOKYO, }), target: target2, }); } }
すると同じエラーが再度発生しました。
$ cdk synth Error: Resolution error: Resolution error: Resolution error: All principals in a PolicyStatement must have the same Conditions (got '{}' and '{"StringEquals":{"aws:SourceAccount":"${Token[AWS.AccountId.9]}"}}'). Use multiple statements instead..
これ、同一スタック内で同じロールを複数の Scheduler 間で共用しようとしてエラーになっているのでしょうか?
その2
次のように 1 つの Scheduler を構成しようとした場合は、もちろんデプロイ含め成功します。
import { aws_lambda_nodejs, aws_lambda, Stack, TimeZone } from 'aws-cdk-lib'; import * as aws_scheduler_alpha from '@aws-cdk/aws-scheduler-alpha'; import * as aws_scheduler_targets_alpha from '@aws-cdk/aws-scheduler-targets-alpha'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id); // Lambda 関数 const helloFunc = new aws_lambda_nodejs.NodejsFunction(this, 'HelloFunc', { runtime: aws_lambda.Runtime.NODEJS_20_X, architecture: aws_lambda.Architecture.ARM_64, }); // Lambda 実行ターゲット const target = new aws_scheduler_targets_alpha.LambdaInvoke(helloFunc, {}); // Scheduler その1 new aws_scheduler_alpha.Schedule(this, 'Shedule1', { schedule: aws_scheduler_alpha.ScheduleExpression.cron({ minute: '0', hour: '1', month: '3', day: '1-31', year: '2024', timeZone: TimeZone.ASIA_TOKYO, }), target, }); } }
そして作成された SchedulerRoleForTarget の Trust Relationship は次のようになっていました。
$ aws iam get-role --role-name $SchedulerRoleForTargetName --query 'Role.AssumeRolePolicyDocument' { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "scheduler.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "aws:SourceAccount": "XXXXXXXXXXXX" } } } ] }
上記のステートメントの Condition
の記述は、
(got '{}' and '{"StringEquals":{"aws:SourceAccount":"${Token[AWS.AccountId.9]}"}}')
とあるうちの後者 {"StringEquals":{"aws:SourceAccount":"${Token[AWS.AccountId.9]}"}}
に該当します。そして事象が発生したパターンでは上記に加えて 2 つ目の {}
が追加されようとして、両者が異なっているためエラーとなったようです。
そこで role プロパティを明示的に指定することにより、冒頭に示した通りエラーを回避できました。
おわりに
AWS CDK の alpha module を利用して Amazon EventBridge Scheduler を構成する際に、 Resolution error: All principals in a PolicyStatement must have the same Conditions
というエラーが発生したので対処した内容を共有しました。
バグのような挙動なので、今後修正される可能性もありますが、現時点では上記のような対処が必要です。注意しつつ活用していきましょう。
参考
以上