如何在AWS CDK中为包含多资源的Construct实现IGrantable接口
组合多个IGrantable资源实现自定义IGrantable Construct方案
完全可以实现该需求,你之前的方案异常主要是两个原因:构造函数未调用父类Construct的super初始化方法,以及CompositePrincipal入参的类型处理不到位。下面提供两种可正常运行的实现方案:
方案1:修复原CompositePrincipal实现
Lambda Function的grantPrincipal本质是执行角色,属于PrincipalBase的子类,做安全类型强转即可使用。注意必须在构造函数第一行完成父类初始化:
import { Construct } from 'constructs'; import { Function, Runtime, Code } from 'aws-cdk-lib/aws-lambda'; import { IGrantable, IPrincipal, CompositePrincipal, PrincipalBase } from 'aws-cdk-lib/aws-iam'; export class MyLambdas extends Construct implements IGrantable { private readonly firstLambda: Function; private readonly secondLambda: Function; public readonly grantPrincipal: IPrincipal; constructor(scope: Construct, id: string) { // 必须先调用父类构造方法,否则Construct初始化异常会导致权限不生效 super(scope, id); this.firstLambda = new Function(this, 'FirstLambda', { runtime: Runtime.NODEJS_18_X, handler: 'index.handler', code: Code.fromInline('exports.handler = () => {}') }); this.secondLambda = new Function(this, 'SecondLambda', { runtime: Runtime.NODEJS_18_X, handler: 'index.handler', code: Code.fromInline('exports.handler = () => {}') }); this.grantPrincipal = new CompositePrincipal( this.firstLambda.grantPrincipal as PrincipalBase, this.secondLambda.grantPrincipal as PrincipalBase ); } }
方案2:自定义组合Principal(更稳妥,无类型强转)
该方案不受CompositePrincipal的入参类型限制,所有权限操作会直接转发给每一个子Principal,兼容性更高,不会出现权限遗漏问题:
import { Construct } from 'constructs'; import { Function } from 'aws-cdk-lib/aws-lambda'; import { IGrantable, IPrincipal, PolicyStatement, AddToPrincipalPolicyResult } from 'aws-cdk-lib/aws-iam'; // 自定义组合Principal类,自动转发所有权限操作到子Principal class CombinedPrincipal implements IPrincipal { public readonly assumeRoleAction: string = 'sts:AssumeRole'; public readonly policyFragment: IPrincipal['policyFragment']; public readonly principalAccount?: string; constructor(private readonly principals: IPrincipal[]) { this.principalAccount = principals[0]?.principalAccount; this.policyFragment = principals[0]?.policyFragment || { principalJson: {} }; } public addToPolicy(statement: PolicyStatement): boolean { let added = false; this.principals.forEach(p => { if (p.addToPolicy(statement)) added = true; }); return added; } public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { let addCount = 0; this.principals.forEach(p => { if (p.addToPrincipalPolicy(statement).statementAdded) addCount++; }); return { statementAdded: addCount > 0, policyDependable: undefined }; } } export class MyLambdas extends Construct implements IGrantable { private readonly firstLambda: Function; private readonly secondLambda: Function; public readonly grantPrincipal: IPrincipal; constructor(scope: Construct, id: string) { super(scope, id); this.firstLambda = new Function(this, 'FirstLambda', { // 填入你的Lambda配置参数 }); this.secondLambda = new Function(this, 'SecondLambda', { // 填入你的Lambda配置参数 }); // 直接传入所有子Principal,无需类型强转 this.grantPrincipal = new CombinedPrincipal([ this.firstLambda.grantPrincipal, this.secondLambda.grantPrincipal ]); } }
使用验证
两种方案实现后,直接调用任意资源的grant方法传入自定义Construct实例即可,权限会自动下发到所有内部Lambda:
import { Bucket } from 'aws-cdk-lib/aws-s3'; const myLambdas = new MyLambdas(this, 'MyLambdas'); const bucket = new Bucket(this, 'MyDataBucket'); // 两个Lambda的执行角色都会自动添加S3桶读取权限 bucket.grantRead(myLambdas);
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

