1
votes

I followed the following tutorial to create a Lambda deploy pipeline using CDK. When I try to keep everything in the same account it works well. https://docs.aws.amazon.com/cdk/latest/guide/codepipeline_example.html

But my scenario is slightly different from the example because it involves two AWS accounts instead one. I maintain application source code and pipeline in the OPS account and this pipeline will deploy the Lambda application to the UAT account.

OPS Account (12345678) - CodeCommit repo & CodePipeline UAT Account (87654321) - Lambda application

As per the aws following aws documentation (Cross-account actions section) I made the following changes to source code. https://docs.aws.amazon.com/cdk/api/latest/docs/aws-codepipeline-actions-readme.html

  • Lambda stack expose deploy action role as follows

    export class LambdaStack extends cdk.Stack {
        public readonly deployActionRole: iam.Role;
    
        constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
            ...
    
            this.deployActionRole = new iam.Role(this, 'ActionRole', {
                assumedBy: new iam.AccountPrincipal('12345678'), //pipeline account
                // the role has to have a physical name set
                roleName: 'DeployActionRole',
            });
        }
    }
    
  • In the pipeline stack,

    new codePipeline.Pipeline(this, 'MicroServicePipeline', {
        pipelineName: 'MicroServicePipeline',
        stages: [
          {
            stageName: 'Deploy',
            actions: [
                new codePipelineAction.CloudFormationCreateUpdateStackAction({
                  role: props.deployActionRole,
                  ....
                })
            ]
          }
        ]
    });
    
  • Following is how I initiate stacks

    const app = new cdk.App();
    
    const opsEnv: cdk.Environment = {account: '12345678', region: 'ap-southeast-2'};
    const uatEnv: cdk.Environment = {account: '87654321', region: 'ap-southeast-2'};
    
    const lambdaStack = new LambdaStack(app, 'LambdaStack', {env: uatEnv});
    
    const lambdaCode = lambdaStack.lambdaCode;
    const deployActionRole = lambdaStack.deployActionRole;
    new MicroServicePipelineStack(app, 'MicroServicePipelineStack', {
        env: opsEnv,
        stackName: 'MicroServicePipelineStack',
        lambdaCode,
        deployActionRole
    });
    
    app.synth();
    
  • AWS credentials profiles looks liks

    [profile uatadmin]
    role_arn=arn:aws:iam::87654321:role/PigletUatAdminRole
    source_profile=opsadmin
    region=ap-southeast-2
    

when I run cdk diff or deploy I get an error saying,

➜  infra git:(master) ✗ cdk diff MicroServicePipelineStack --profile uatadmin
Including dependency stacks: LambdaStack
Stack LambdaStack
Need to perform AWS calls for account 87654321, but no credentials have been configured.

What have I done wrong here? Is it my CDK code or is it the way I have configured my AWS profile?

Thanks, Kasun

3
Take a look at my answer here : stackoverflow.com/a/60064619/9931092 - Amit Baranes
Thanks @AmitBaranes - Dilunika
Amit, Yes, I can achieve it using codebuild which I need to build the binaries in every stage. However, I am trying to use CFN action here in order to use the CFN script generated in the Build stage. As AWS example stated. That is the best practice when it comes to DeoOps pipeline. That is why I try to achieve in that way. But seems like I have to fall back to the code build approach now. - Dilunika
Hi @Dilunika I am trying to achieve the same workflow as you described. Have you found a chance to solve this? - quartaela
Hi @quartaela, above issue is solved using cross account policy. See this gist gist.github.com/dilunika/f1f095af7d30d5582ef0fe1bdbc63832. You have to make sure each trusted entities are correctly set in the role for relevant account roots. However, still pipeline doesn't work as I needed since there is dependency for lambda code. (you will notice that in AWS example). So, I am unable to post the complete working solution yet. - Dilunika

3 Answers

0
votes

The problem is with your AWS CLI configuration. You cannot use the CDK CLI natively to deploy resources in two separate accounts with one CLI command. There is a recent blog post on how to tell CDK which credentials to use, depending on the stack environment parameter: https://aws.amazon.com/blogs/devops/cdk-credential-plugin/

The way we use it is to deploy stacks into separate accounts with multiple CLI commands specifying the required profile. All parameters that need to be exchanged (such as the location of your lambdaCode) is passed via e.g. environment variables.

0
votes

Just try to use using the environment variables: AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION

https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html

Or

~/.aws/credentials

[default]
aws_access_key_id=****
aws_secret_access_key=****

~/.aws/config

[default]
region=us-west-2
output=json

https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html

It works for me.

I'm using cdk version 1.57.0

0
votes

The issue is in the fact that you have resources that exist in multiple accounts and hence there are different credentials required to create those resources. However, CDK does not understand natively how to get credentials for those different accounts or when to swap between the different credentials. One way to fix this is to use cdk-assume-role-credential-plugin, which will allow you to use a single CDK deploy command to deploy to many different accounts.

I wrote a detailed tutorial here: https://johntipper.org/aws-cdk-cross-account-deployments-with-cdk-pipelines-and-cdk-assume-role-credential-plugin/