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.txt と iam-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 ロール/ポリシーを自前で作成して customizeRoles の usePrecreatedRoles に指定することで、安全に IAM ロールの自前管理に切り替えることができます。
const stack = new Stack(app, 'LambdaStack'); iam.Role.customizeRoles(stack, { usePrecreatedRoles: { 'LambdaStack/Handler/ServiceRole': 'lambda-service-role', }, });
なお、上記例は CDK リポジトリの Wiki のSecurity And Safety Dev Guide と 公式ドキュメントの Define permissions for L2 constructs with the AWS CDK から例を引用していますので、詳細はそちらも参照してください。
最後に
CDK で、IAM ロールや権限(ポリシー)の生成/付与を L2 Construct による自動生成に任せたくない人は覚えておくと良いでしょう。