[AWS CDK] EventBridge Scheduler の Universal Target で IAM ポリシーにワイルドカード (*) が自動付与される問題の解決方法

[AWS CDK] EventBridge Scheduler の Universal Target で IAM ポリシーにワイルドカード (*) が自動付与される問題の解決方法

結論: policyStatements の明示的な指定により解決できました。
2026.01.10

こんにちは、製造ビジネステクノロジー部の若槻です。

Amazon EventBridge Scheduler では Universal Targets を使用することで、Lambda や Step Functions、ECS タスクなど様々な AWS サービスをターゲットにスケジュール実行できます。

https://docs.aws.amazon.com/ja_jp/scheduler/latest/UserGuide/managing-targets-universal.html

Universal Targets は AWS CDK の L2 コンストラクトとしても提供されており、以下のドキュメントで使用方法が紹介されています。

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_scheduler_targets.Universal.html

今回は、この EventBridge Scheduler の Universal Target を CDK で使用する際に、IAM ポリシーにワイルドカード (*) が自動付与される問題の解決方法 について紹介します。

問題

次のように Lambda の Provisioned Concurrency を有効化する EventBridge Scheduler を作成するコンストラクトを実装しました。

Scheduler の Universal Target に設定する IAM ロールは明示的に作成し、最小権限の権限ポリシーとしています。

lib/constructs/enable-pc-scheduler/index.ts(未解決)
// Warning 発生: 未解決
// ワイルドポリシー自動付与: 未解決
import * as cdk from "aws-cdk-lib";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as scheduler from "aws-cdk-lib/aws-scheduler";
import * as scheduler_targets from "aws-cdk-lib/aws-scheduler-targets";
import { Construct } from "constructs";

interface EnablePcSchedulerProps {
  alias: lambda.Alias;
}

/**
 * Lambda の Provisioned Concurrency を有効化する Scheduler を作成する Construct
 */
export class EnablePcScheduler extends Construct {
  constructor(scope: Construct, id: string, props: EnablePcSchedulerProps) {
    super(scope, id);

    const { alias } = props;

    /**
     * 最小権限の IAM Role の作成
     */
    const role = new iam.Role(this, "Role", {
      assumedBy: new iam.ServicePrincipal("scheduler.amazonaws.com"),
    });
    role.addToPolicy(
      new iam.PolicyStatement({
        actions: ["lambda:PutProvisionedConcurrencyConfig"],
        resources: [alias.functionArn],
      })
    );

    /**
     * Scheduler Target の作成
     */
    const target = new scheduler_targets.Universal({
      service: "lambda",
      action: "putProvisionedConcurrencyConfig",
      role, // 作成した IAM Role を明示的に指定
      input: scheduler.ScheduleTargetInput.fromObject({
        FunctionName: alias.functionName,
        Qualifier: alias.aliasName,
        ProvisionedConcurrentExecutions: 5,
      }),
    });

    /**
     * 平日9時に Provisioned Concurrency を有効化する Scheduler の作成
     */
    new scheduler.Schedule(this, "Default", {
      schedule: scheduler.ScheduleExpression.cron({
        minute: "0",
        hour: "9-18",
        weekDay: "MON-FRI",
        timeZone: cdk.TimeZone.ASIA_TOKYO,
      }),
      target,
    });
  }
}

しかし上記をデプロイするとコマンド実行結果に以下の Warning が表示されました。

[Warning at /Sample/EnablePcScheduler/Role] Default policy with * for resources is used. Use custom policy for better security posture. [ack: @aws-cdk/aws-scheduler-targets:defaultWildcardResourcePolicy]

作成された IAM Policy を見ると、Resource 句に明示的に指定した ARN に加え、ワイルドカード (*)が追加されていました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "lambda:PutProvisionedConcurrencyConfig",
      "Resource": [
        "*",
        "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:Sample-SampleFunction7DB1D36A-KZtPV8JOPRdt:Prod"
      ],
      "Effect": "Allow"
    }
  ]
}

警告の通り、L2 コンストラクトで内部的にデフォルトでワイルドカードの権限自動付与が行われているようですが、セキュリティを考慮すると望ましくはありませんね。

解決

次のように、policyStatements プロパティで明示的にポリシーステートメントを指定することで、ワイルドカードの権限自動付与および警告の発生を抑制できました。

lib/constructs/enable-pc-scheduler/index.ts
import * as cdk from "aws-cdk-lib";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as scheduler from "aws-cdk-lib/aws-scheduler";
import * as scheduler_targets from "aws-cdk-lib/aws-scheduler-targets";
import { Construct } from "constructs";

interface EnablePcSchedulerProps {
  alias: lambda.Alias;
}

/**
 * Lambda の Provisioned Concurrency を有効化するスケジューラーを作成する Construct
 */
export class EnablePcScheduler extends Construct {
  constructor(scope: Construct, id: string, props: EnablePcSchedulerProps) {
    super(scope, id);

    const { alias } = props;

    /**
     * Scheduler Target の作成
     */
    const target = new scheduler_targets.Universal({
      service: "lambda",
      action: "putProvisionedConcurrencyConfig",

      /**
       * 権限自動付与を回避するため、policyStatements で明示的に権限を指定する。
       * @see https://github.com/aws/aws-cdk/blob/068c9f90160e21503eca091c9db4b339f669e2dd/packages/aws-cdk-lib/aws-scheduler-targets/lib/universal.ts#L96
       */
      policyStatements: [
        new iam.PolicyStatement({
          actions: ["lambda:PutProvisionedConcurrencyConfig"],
          resources: [alias.functionArn],
        }),
      ],

      input: scheduler.ScheduleTargetInput.fromObject({
        FunctionName: alias.functionName,
        Qualifier: alias.aliasName,
        ProvisionedConcurrentExecutions: 5,
      }),
    });

    /**
     * 平日9時に Provisioned Concurrency を有効化するスケジューラー
     */
    new scheduler.Schedule(this, "Default", {
      schedule: scheduler.ScheduleExpression.cron({
        minute: "0",
        hour: "9-18",
        weekDay: "MON-FRI",
        timeZone: cdk.TimeZone.ASIA_TOKYO,
      }),
      target,
    });
  }
}

上記をデプロイすると、作成された IAM ポリシーは以下の通りとなり、ワイルドカードの権限自動付与および警告の発生も抑制されました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "lambda:PutProvisionedConcurrencyConfig",
      "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:Sample-SampleFunction7DB1D36A-KZtPV8JOPRdt:Prod",
      "Effect": "Allow"
    }
  ]
}

解説ですが、下記の Universal クラスのソースコードを確認すると、policyStatements を省略すると「*(全リソース)」の権限を自動的に追加し、警告もセットで出す仕様となっています。

https://github.com/aws/aws-cdk/blob/068c9f90160e21503eca091c9db4b339f669e2dd/packages/aws-cdk-lib/aws-scheduler-targets/lib/universal.ts#L96-L109

よって、ワイルドカードを避けて最小権限で運用したい場合は、policyStatements を明示的に記述する必要があるのですね。

別解

当初、policyStatements プロパティを指定する方法に気づかず、別の方法でワイルドカードの権限自動付与および警告の発生を抑制できましたので、参考までに紹介します。

ちなみにいずれの方法も acknowledgeWarning() により明示的な警告抑制が必要となりました。

その1: withoutPolicyUpdates() による方法

次の2つの対応により、ワイルドカードの権限自動付与および警告の発生を抑制できました。

  • 最小権限の IAM ロールを作成し、role.withoutPolicyUpdates() を使用してターゲットに渡す
  • Annotations.of(node).acknowledgeWarning() を使用して警告を抑制する
方法詳細
lib/constructs/enable-pc-scheduler/index.ts
import * as cdk from "aws-cdk-lib";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as scheduler from "aws-cdk-lib/aws-scheduler";
import * as scheduler_targets from "aws-cdk-lib/aws-scheduler-targets";
import { Construct } from "constructs";

interface EnablePcSchedulerProps {
  alias: lambda.Alias;
}

/**
 * Lambda の Provisioned Concurrency を有効化するスケジューラーを作成する Construct
 */
export class EnablePcScheduler extends Construct {
  constructor(scope: Construct, id: string, props: EnablePcSchedulerProps) {
    super(scope, id);

    const { alias } = props;

    /**
     * 最小権限の IAM Role の作成
     */
    const role = new iam.Role(this, "Role", {
      assumedBy: new iam.ServicePrincipal("scheduler.amazonaws.com"),
    });
    role.addToPolicy(
      new iam.PolicyStatement({
        actions: ["lambda:PutProvisionedConcurrencyConfig"],
        resources: [alias.functionArn],
      })
    );

    /**
     * Scheduler Target の作成
     */
    const target = new scheduler_targets.Universal({
      service: "lambda",
      action: "putProvisionedConcurrencyConfig",
      role: role.withoutPolicyUpdates(), // ポリシー自動更新を無効化してワイルドカード付与を防止
      input: scheduler.ScheduleTargetInput.fromObject({
        FunctionName: alias.functionName,
        Qualifier: alias.aliasName,
        ProvisionedConcurrentExecutions: 5,
      }),
    });

    /**
     * 平日9時に Provisioned Concurrency を有効化するスケジューラー
     */
    new scheduler.Schedule(this, "Default", {
      schedule: scheduler.ScheduleExpression.cron({
        minute: "0",
        hour: "9-18",
        weekDay: "MON-FRI",
        timeZone: cdk.TimeZone.ASIA_TOKYO,
      }),
      target,
    });

    /**
     * Universal が内部的に生成するロールの警告を抑制
     */
    cdk.Aspects.of(scope).add({
      visit(node) {
        cdk.Annotations.of(node).acknowledgeWarning(
          "@aws-cdk/aws-scheduler-targets:defaultWildcardResourcePolicy"
        );
      },
    });
  }
}

上記をデプロイすると、作成された IAM ポリシーは以下の通りとなり、ワイルドカードの権限自動付与および警告の発生も抑制されました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "lambda:PutProvisionedConcurrencyConfig",
      "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:Sample-SampleFunction7DB1D36A-KZtPV8JOPRdt:Prod",
      "Effect": "Allow"
    }
  ]
}

withoutPolicyUpdates() を使用すると元の Role オブジェクトをポリシーが変更不能な ImmutableRole に変換でき、L2 コンストラクトによる権限自動付与を防止できます。下記で詳しく解説されています。

https://dev.classmethod.jp/articles/aws-cdk-immutable-role-guard-change-policy/

その2: エスケープハッチによる方法

エスケープハッチを使用して target ロールを role で置き換えることにより、権限自動付与を無効化することもできます。

方法詳細
lib/constructs/enable-pc-scheduler/index.ts
import * as cdk from "aws-cdk-lib";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as scheduler from "aws-cdk-lib/aws-scheduler";
import * as scheduler_targets from "aws-cdk-lib/aws-scheduler-targets";
import { Construct } from "constructs";

interface EnablePcSchedulerProps {
  alias: lambda.Alias;
}

/**
 * Lambda の Provisioned Concurrency を有効化するスケジューラーを作成する Construct
 */
export class EnablePcScheduler extends Construct {
  constructor(scope: Construct, id: string, props: EnablePcSchedulerProps) {
    super(scope, id);

    const { alias } = props;

    /**
     * 最小権限の IAM Role の作成
     */
    const role = new iam.Role(this, "Role", {
      assumedBy: new iam.ServicePrincipal("scheduler.amazonaws.com"),
    });
    role.addToPolicy(
      new iam.PolicyStatement({
        actions: ["lambda:PutProvisionedConcurrencyConfig"],
        resources: [alias.functionArn],
      })
    );

    /**
     * Scheduler Target の作成
     */
    const target = new scheduler_targets.Universal({
      service: "lambda",
      action: "putProvisionedConcurrencyConfig",
      input: scheduler.ScheduleTargetInput.fromObject({
        FunctionName: alias.functionName,
        Qualifier: alias.aliasName,
        ProvisionedConcurrentExecutions: 5,
      }),
    });

    /**
     * エスケープハッチを使用して target ロールを role で置き換える
     */
    (target as any).role = role;

    /**
     * 平日9時に Provisioned Concurrency を有効化するスケジューラー
     */
    new scheduler.Schedule(this, "Default", {
      schedule: scheduler.ScheduleExpression.cron({
        minute: "0",
        hour: "9-18",
        weekDay: "MON-FRI",
        timeZone: cdk.TimeZone.ASIA_TOKYO,
      }),
      target,
    });

    /**
     * Universal が内部的に生成するロールの警告を抑制
     */
    cdk.Aspects.of(scope).add({
      visit(node) {
        cdk.Annotations.of(node).acknowledgeWarning(
          "@aws-cdk/aws-scheduler-targets:defaultWildcardResourcePolicy"
        );
      },
    });
  }
}

上記をデプロイすると、作成された IAM ポリシーは以下の通りとなり、ワイルドカードの権限自動付与および警告の発生も抑制されました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "lambda:PutProvisionedConcurrencyConfig",
      "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:Sample-SampleFunction7DB1D36A-KZtPV8JOPRdt:Prod",
      "Effect": "Allow"
    }
  ]
}

おわりに

Amazon EventBridge Scheduler の Universal Target を CDK で使用する際に、IAM ポリシーにワイルドカード (*) が自動付与される問題の解決方法について紹介しました。

ワイルドカードによる過剰な権限付与はセキュリティリスクとなります。CDK デプロイ時の警告を無視したり、無闇に抑制したりせずに、今回紹介したように policyStatements プロパティを使用して最小権限のポリシーステートメントを明示的に指定することをお勧めします。

以上

この記事をシェアする

FacebookHatena blogX

関連記事