Table of Contents
- Table of Contents
- Automatic IAM Role Generation in L2 Constructs
- withoutPolicyUpdates()
- mutable in fromRoleArn()
- Role.customizeRoles()
- Conclusion
Automatic IAM Role Generation in L2 Constructs
One of the major features of AWS CDK is that most L2 Constructs automatically generate IAM roles with the necessary permissions for the resources.
On the other hand, most Constructs also allow you to pass a custom role you created yourself, so you can avoid automatic generation.
However, even in that case, the L2 Construct often automatically grants the necessary permissions to the custom role you created and passed.
withoutPolicyUpdates()
However, if you want to manage IAM roles yourself, you may also want to manage the policies yourself, so there may be cases where you want to avoid having permissions automatically granted to your custom role within the L2 Construct.
In such cases, you can use the withoutPolicyUpdates() method of the Role Construct to avoid automatic permission grants to your custom role.
const role = new iam.Role(stack, 'ExecutionRole', {
assumedBy: new iam.ServicePrincipal('bedrock-agentcore.amazonaws.com'),
});
// Add the necessary policies yourself
role.addToPrincipalPolicy(statement);
new agentcore.Runtime(stack, 'TestRuntime', {
runtimeName: 'integ_test_runtime',
agentRuntimeArtifact: runtimeArtifact,
executionRole: role.withoutPolicyUpdates(), // Pass the return value of withoutPolicyUpdates(), not role
});
mutable in fromRoleArn()
In CDK, you can pseudo-import a role created outside the stack into the CDK stack using static methods such as fromRoleArn() of the Role Construct.
This allows you to use the convenient methods provided by the Construct in your CDK code even for manually created resources, making it a very useful feature.
For IAM roles imported with the fromRoleArn() method, you can also set mutable: false to prevent policies from being automatically attached.
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()
Using the Role.customizeRoles() method, you can output a report of what IAM roles and policies would be generated by L2 Constructs without actually creating them.
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);
This generates two files: iam-policy-report.txt and iam-policy-report.json.
<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)"
}
]
}
]
}
Based on this report, you can create IAM roles/policies yourself and specify them in the usePrecreatedRoles option of customizeRoles to safely switch to self-managing IAM roles.
const stack = new Stack(app, 'LambdaStack');
iam.Role.customizeRoles(stack, {
usePrecreatedRoles: {
'LambdaStack/Handler/ServiceRole': 'lambda-service-role',
},
});
NOTE: The above examples are quoted from the Security And Safety Dev Guide in the CDK repository's Wiki and the official documentation Define permissions for L2 constructs with the AWS CDK, so please refer to them for more details.
Conclusion
If you don't want to leave the generation/granting of IAM roles and permissions (policies) to automatic generation by L2 Constructs in CDK, it would be good to remember these methods.
Top comments (0)