AWS CDK における IAM ロールへのポリシー自動付与の制御方法

AWS CDK における IAM ロールの豆知識を紹介します。

目次

目次


L2 Construct の IAM ロールの自動生成

AWS CDK の大きな特徴の一つとして、基本的にはだいたいの L2 Construct の中で、そのリソースに必要な権限を付与した IAM ロールを自動で生成してくれます。


一方で、だいたいの Construct では自前で作成したロールも渡せるので、自動生成を避けられます。

しかしその場合でも、自前で作成して渡したロールにも、そのリソースに必要な権限を L2 Construct が内部で自動で付与することも多いです。


withoutPolicyUpdates()

しかし自前で IAM ロールを管理したい場合、そのポリシーも自分で管理したいことがあるため、L2 Construct の中で自前のロールに自動で権限が付与されてしまうのは避けたいケースもあるでしょう。

そんなとき、Role Construct の withoutPolicyUpdates() メソッドを使うと、自前ロールへの権限の自動付与を回避できます。

const role = new iam.Role(stack, 'ExecutionRole', {
  assumedBy: new iam.ServicePrincipal('bedrock-agentcore.amazonaws.com'),
});

// 必要なポリシーを自分で追加
role.addToPrincipalPolicy(statement);

new agentcore.Runtime(stack, 'TestRuntime', {
  runtimeName: 'integ_test_runtime',
  agentRuntimeArtifact: runtimeArtifact,
  executionRole: role.withoutPolicyUpdates(), // role でなく withoutPolicyUpdates() の戻り値を渡す
});


fromRoleArn() の mutable

また CDK では、スタック外で作成したロールを、Role Construct の fromRoleArn() などの static メソッドを使用して CDK スタック内に擬似的にインポートすることができます。

これにより、手動で作成したリソースでも CDK コード内で Construct の提供する便利メソッドを使うことができるため、非常に便利な機能です。


そこで、fromRoleArn() メソッドでインポートした IAM ロールに関しても、mutable: false にすることで、自動でポリシーをアタッチされるのを防ぐことができます。

const importedRole = iam.Role.fromRoleArn(stack, 'ImportedRole', 'my-role-arn', {
  mutable: false,
});

new agentcore.Runtime(stack, 'TestRuntime', {
  runtimeName: 'integ_test_runtime',
  agentRuntimeArtifact: runtimeArtifact,
  executionRole: importedRole,
});


Role.customizeRoles()

Role.customizeRoles() メソッドを使用すると、L2 Construct で生成される IAM ロールやポリシーを、実際には作成せずに何が生成されるのかをレポートとして書き出すことができます。

const app = new cdk.App();
const stack = new cdk.Stack(app, 'LambdaStack');

iam.Role.customizeRoles(stack);

const key = new kms.Key(stack, 'BucketKey');
const bucket = new s3.Bucket(stack, 'Bucket', {
  encryptionKey: key,
});
const handler = new lambda.Function(stack, 'Handler', {
  runtime: lambda.Runtime.NODEJS_22_X,
  handler: 'index.handler',
  code: lambda.Code.fromInline(`
    exports.handler = async function(event, context) {
      console.log("Event: ", event);
      return;
    };
  `),
});

bucket.grantRead(handler);


これにより、iam-policy-report.txtiam-policy-report.json という 2 つのファイルが生成されます。

<missing role> (LambdaStack/Handler/ServiceRole)

AssumeRole Policy:
[
  {
    "Action": "sts:AssumeRole",
    "Effect": "Allow",
    "Principal": {
      "Service": "lambda.amazonaws.com"
    }
  }
]

Managed Policy ARNs:
[
  "arn:(PARTITION):iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]

Managed Policies Statements:
NONE

Identity Policy Statements:
[
  {
    "Action": [
      "s3:GetObject*",
      "s3:GetBucket*",
      "s3:List*"
    ],
    "Effect": "Allow",
    "Resource": [
      "(LambdaStack/Bucket/Resource.Arn)",
      "(LambdaStack/Bucket/Resource.Arn)/*"
    ]
  },
  {
    "Action": [
      "kms:Decrypt",
      "kms:DescribeKey"
    ],
    "Effect": "Allow",
    "Resource": "(LambdaStack/BucketKey/Resource.Arn)"
  }
]
{
  "roles": [
    {
      "roleConstructPath": "LambdaStack/Handler/ServiceRole",
      "roleName": "missing role",
      "missing": true,
      "assumeRolePolicy": [
        {
          "Action": "sts:AssumeRole",
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          }
        }
      ],
      "managedPolicyArns": ["arn:(PARTITION):iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],
      "managedPolicyStatements": [],
      "identityPolicyStatements": [
        {
          "Action": ["s3:GetObject*", "s3:GetBucket*", "s3:List*"],
          "Effect": "Allow",
          "Resource": ["(LambdaStack/Bucket/Resource.Arn)", "(LambdaStack/Bucket/Resource.Arn)/*"]
        },
        {
          "Action": ["kms:Decrypt", "kms:DescribeKey"],
          "Effect": "Allow",
          "Resource": "(LambdaStack/BucketKey/Resource.Arn)"
        }
      ]
    }
  ]
}


こちらのレポートをもとに IAM ロール/ポリシーを自前で作成して customizeRolesusePrecreatedRoles に指定することで、安全に IAM ロールの自前管理に切り替えることができます。

const stack = new Stack(app, 'LambdaStack');

iam.Role.customizeRoles(stack, {
  usePrecreatedRoles: {
    'LambdaStack/Handler/ServiceRole': 'lambda-service-role',
  },
});


なお、上記例は CDK リポジトリWikiSecurity And Safety Dev Guide と 公式ドキュメントの Define permissions for L2 constructs with the AWS CDK から例を引用していますので、詳細はそちらも参照してください。


最後に

CDK で、IAM ロールや権限(ポリシー)の生成/付与を L2 Construct による自動生成に任せたくない人は覚えておくと良いでしょう。