6

I'm reading the CDK docs about the SecretsManager and I'm not sure if I've mis-understood, but what I thought would work from their example doesn't seem to grant the permission I expected. Essentially I have a stack that contains some Lambdas, and I'd like all of them to be able to Read two secrets from the SecretsManager.

class CdkStack extends cdk.Stack {
    /**
     *
     * @param {cdk.Construct} scope
     * @param {string} id
     * @param {cdk.StackProps=} props
     */
    constructor(scope, id, props) {
        super(scope, id, props);

        // eslint-disable-next-line no-new
        new APIServices(this, "APIServices");

        const role = new iam.Role(this, "SecretsManagerRead", {
            assumedBy: new iam.AccountRootPrincipal(),
        });

        const dbReadSecret = new secretsmanager.Secret(this, "databaseReader");
        const dbWriteSecret = new secretsmanager.Secret(this, "databaseWriter");

        dbReadSecret.grantRead(role);
        dbWriteSecret.grantRead(role);
    }
}

If I understood it correctly I should simply create this role and give it permissions to access secrets? My Lambda's still however failed when I tried to run them. Do I need to do anything else not mentioned in the docs I was reading about assigning that role to the Lambdas explicitly too?

Ian
  • 33,605
  • 26
  • 118
  • 198
  • Did you add this after the Lambda was deployed? If so it may have already assumed and would need to have assumed the role again. Also this code is creating the role but not associating it with a Lambda :( – Chris Williams Jun 07 '20 at 13:04
  • Did you add this role to the Lambda function as its execution role? – Dennis Traub Jun 07 '20 at 13:05
  • I did add this after the lands was already deployed. @DennisTraub how would you go about associating the additional role with the Lamda? – Ian Jun 07 '20 at 13:40
  • A Lambda function can only assume one execution role. You would either have to add a policy with the above permissions to the existing role or replace the role attached to the existing Lambda function with your new one. – Dennis Traub Jun 07 '20 at 13:44
  • @DennisTraub thanks! Do you have any links to examples? Or if you pop an answer in with an example and it works then I can accept :) – Ian Jun 07 '20 at 13:46
  • I've created an answer, showing how you can add the permissions to the existing role. – Dennis Traub Jun 07 '20 at 13:57

1 Answers1

9

Depending on your actual context there are two possible variants.

1. Import existing role

If the Lambda function has been predefined (e.g. in a different stack), you can add the additional permissions to the existing Lambda execution role by importing it into this CDK stack first.

class CdkStack extends cdk.Stack {
    constructor(scope, id, props) {
        // ...

        // Import the existing role into the stack
        const roleArn = 'arn:aws:iam::123456789012:role/MyExistingLambdaExecutionRole'
        const role = iam.Role.fromRoleArn(this, 'Role', roleArn, {
            mutable: true,
        });

        const dbReadSecret = new secretsmanager.Secret(this, "databaseReader");
        const dbWriteSecret = new secretsmanager.Secret(this, "databaseWriter");

        dbReadSecret.grantRead(role);
        dbWriteSecret.grantRead(role);
    }
}

For more information regarding the usage of the aws-iam CDK module, here's the link to the documentation. Here, you can learn more about the Lambda Execution Role itself.

2. Lambda function defined as part of stack

If the lambda function has been defined somewhere in this stack, you can simply attach the permissions to the Lambda function through its reference using dbReadSecret.grantRead(lambda.role) and dbWriteSecret.grantRead(lambda.role) respectively.

class CdkStack extends cdk.Stack {
    constructor(scope, id, props) {
        // ...

        // Create the function or retrieve the reference if 
        // it has been defined somewhere else in the stack

        const lambda = ...

        const dbReadSecret = new secretsmanager.Secret(this, "databaseReader");
        const dbWriteSecret = new secretsmanager.Secret(this, "databaseWriter");

        dbReadSecret.grantRead(lambda.role);
        dbWriteSecret.grantRead(lambda.role);
    }
}

Please have a look at the answer to this question for reference.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • Thanks, so just a follow up. This is modifying the role write? How do I obtain the roleArn when this CDK stack itself is most likely creating that in the first place? – Ian Jun 07 '20 at 14:54
  • I understood that the Lambda function already existed. Which means there should be an existing role associated. – Dennis Traub Jun 07 '20 at 14:58
  • Please clarify if the Lambda function is part of the stack or if the Lambda function already exists. – Dennis Traub Jun 07 '20 at 14:58
  • Yeah, sorry. The APIServices defines both a Lamda function and an ApiGateway. – Ian Jun 07 '20 at 15:13
  • Then you can simply attach the permissions to the Lambda function through its reference using `dbReadSecret.grantRead(lambda.role)` and `dbWriteSecret.grantRead(lambda.role)` respectively. – Dennis Traub Jun 07 '20 at 17:32
  • 1
    Please have a look at the answer to this question for reference: https://stackoverflow.com/questions/52636929/specifying-a-custom-role-for-lambda-with-the-aws-cdk – Dennis Traub Jun 07 '20 at 17:36
  • I've integrated my above comments into the answer. – Dennis Traub Jun 07 '20 at 17:42
  • Thanks, will take a look shortly and accept if it resolves my problem, which I think it will scanning it. CDK docs aren't that great I'm finding – Ian Jun 07 '20 at 17:47
  • 1
    Happy to help. Let me know if you there's still something missing. And regarding the documentation: It's an open source project, so please feel free to contribute ;-) – Dennis Traub Jun 07 '20 at 17:48
  • Thanks a bunch. That worked, I had to use `Secret.fromSecretArn()` in the end as the secret wasn't part of the stack and I hadn't realised I was creating new ones. But basically the `grantRead` bit was the bit I was missing. – Ian Jun 07 '20 at 20:57
  • Great! Thanks for letting me know that you got it to work. – Dennis Traub Jun 07 '20 at 21:00
  • Just checked out your profile - I'm sure you'll be seeing a lot more of my questions over the coming weeks :D – Ian Jun 07 '20 at 21:01