Search code examples
typescriptamazon-iamaws-cdkaws-roles

CDK - Add policies to role with For each


I'm trying to create a Role with some policies, which will differ from lambda to lambda. The ideal scenario would be to have a function where the role and policies are all created and then I'd just call the function and give it the name of the role and the policies I wanted attached, and it would create all of it. So far I have this:

Usage of lambda role creation:

...
    const lambdarole = this.createLambdaRole( 'Test Role', [
      'KMSLambdaPolicy',
      'S3LambdaPolicy',
    ]);
...

Role and policies creation:

  private createLambdaRole(roleName: string, policyName: string[]) {
    const role = new Role(this, 'Role', {
      roleName: roleName,
      assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
      description: 'Role for lambda access',
      managedPolicies: [],
    });

    const kmspolicy = new ManagedPolicy(this, 'KMSLambdaPolicy', {
      managedPolicyName: 'KMSLambdaPolicy',
      statements: [
        new PolicyStatement({
          effect: Effect.ALLOW,
          actions: [
            'kms:Decrypt',
            'kms:GenerateDataKey',
            'kms:DescribeKey'],
        }),
      ],
    });

    const s3policy = new ManagedPolicy(this, 'S3LambdaPolicy', {
      managedPolicyName: 'S3LambdaPolicy',
      statements: [
        new PolicyStatement({
          effect: Effect.ALLOW,
          actions: [
            's3:PutObject',
            's3:GetObject',
            's3:GetObjectAttributes'],
          resources: ['*'],
        }),
      ],
    });

    policyName.forEach(policyName => role.addManagedPolicy(policyName));

    return role;
  }

Currently I can't get it to work, and it gives the following error:

error TS2345: Argument of type 'string' is not assignable to parameter of type 'IManagedPolicy'.

Is what I want even possible?

Thank you in advance for anyone willing to help!

SOLUTION FOUND

I managed to make it work with the code bellow:

policyName.forEach(policyName => {
  const importedPolicy = ManagedPolicy.fromManagedPolicyName(this, policyName, policyName);
  role.addManagedPolicy(importedPolicy);
});

Note: addManagedPolicy requires a scope, an id and a policy name. Since my policy ID's and names are the same, I just needed to call the array again (hence the this, policyName, policyName).


Solution

  • The addManagedPolicy expects an IManagedPolicy object, but you provided a string instead.

        // the managed policy definition is only needed once for your whole account,
        // if you want to reuse it. 
        // It has to be unique if you want to map it by name.
        // the following is an example for a customer-managed policy.
        // the attribute `managedPolicyName` is the identifier for the 
        // import later on.
        const kmspolicy = new ManagedPolicy(this, 'MP-KMSLambda', {
          managedPolicyName: 'KMSLambdaPolicy'
          // etc.
        }); 
    
    
        // the following role attachment can happen everywhere in your CDK application, 
        // e.g. in another construct or stack.
        //
        // The policyNames list need to have the same identifier as in
        // your new ManagedPolicies before.
        const policyNames = ['KMSLambdaPolicy'];
        policyNames.forEach(policyName => {
           const importedPolicy = iam.ManagedPolicy.fromManagedPolicyName(this, `${role.roleName}-${policyName}`, policyName)
           role.addManagedPolicy(importedPolicy)
        });