skip to Main Content

I’m trying to setup a cross-account pipeline to deploy website artifact to S3 buckets that already exist in the AWS accounts. And the pipeline(which is hosted in Alpha/Tool account) throws error when deploy to prod AWS.

I create those S3 buckets first with a different cloudformation stack.

I have two AWS accounts, alpha 111111 and prod 222222. And I bootstrap both following this tutorial https://aws.plainenglish.io/cdk-cross-account-pipelines-part-2-dcb5517a0610.

Basically I did:

// Bootstrap Alpha
cdk bootstrap aws://111111/us-east-1  --profile=eCommerceWebsite-Alpha

// Bootstrap Prod
cdk bootstrap --profile=eCommerceWebsite-Prod --bootstrap-customer-key --cloudformation-execution-policies 'arn:aws:iam::aws:policy/AdministratorAccess' --trust 111111 --trust-for-lookup 111111  aws://222222/us-east-1 

I’m using CDK V2 which the configuration is different from CDK v1.CDK v2 has naive support for cross account deployment so that don’t need to manually create cross-account deployment roles. https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html#bootstrapping-template

pipeline-config.ts:

export const pipelineStageInfoList: PipelineStageInfo[] = [
    {
        stageName: "ALPHA",
        awsAccount: alphaAwsAccountNumber,
        awsRegion: defaultAwsRegion,
        websiteDomain: alphaWebsiteDomain,
        websiteBucketName: `${alphaWebsiteDomain}-${alphaAwsAccountNumber}-${defaultAwsRegion}`
    },
    {
        stageName: "PROD",
        awsAccount: prodAwsAccountNumber,
        awsRegion: defaultAwsRegion,
        websiteDomain: prodWebsiteDomain,
        websiteBucketName: `${prodWebsiteDomain}-${prodAwsAccountNumber}-${defaultAwsRegion}`
    }
]
   

This is my pipeline code:

export class CodePipelineStack extends CDK.Stack {
    constructor(scope: CDK.App, id: string, props: CodePipelineStackProps) {
      super(scope, id, props);
  
      // Create the pipeline
      const pipeline = new codepipeline.Pipeline(this, props.pipelineName, {
        pipelineName: props.pipelineName,
        restartExecutionOnUpdate: true,
      });

      ...
      // Add deploy stages to this pipeline.
    pipelineStageInfoList.forEach((pipelineStage: PipelineStageInfo) => {
      const websiteBucket = S3.Bucket.fromBucketName(
        this,
        `${pipelineStage.websiteBucketName}ConstructId`,
        `${pipelineStage.websiteBucketName}`
      );

      // Not working for prod stage S3 bucket
      websiteBucket.grantWrite(pipeline.role);
      websiteBucket.grantPut(pipeline.role);

      const applicationStage = new ApplicationStage(
        this,
        pipelineStage.stageName,
        {
          stageName: pipelineStage.stageName,
          pipelineName: props.pipelineName,
          websiteDomain: pipelineStage.websiteDomain,
          websiteBucket: websiteBucket,
          env: {
            account: pipelineStage.awsAccount,
            region: pipelineStage.awsRegion,
          },
        }
      );
      const stage = pipeline.addStage(applicationStage);
      stage.addAction(
        new codepipeline_actions.S3DeployAction({
          actionName: "Deploy-Website",
          input: outputWebsite,
          bucket: websiteBucket,
        })
      );
    });
    }
}

Unfortunately, I get this error: You do not have sufficient permissions to call s3.putObject for the deployment bucket...

enter image description here

I checked my prod webiste S3 bucket. Looks like it doesn’t have any permission setup for the pipeline.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::222222:role/PROD-WebsiteBucket-Stack-CustomS3AutoDeleteObjects-1HFPULRP27KAX"
            },
            "Action": [
                "s3:GetBucket*",
                "s3:List*",
                "s3:DeleteObject*"
            ],
            "Resource": [
                "arn:aws:s3:::dummy.com-222222-us-east-1",
                "arn:aws:s3:::dummy.com-222222-us-east-1/*"
            ]
        }
    ]
}

If you look at my pipeline code, you see that I tried to grant the pipeline role with bucket write permissions websiteBucket.grantWrite(pipeline.role); websiteBucket.grantPut(pipeline.role);. First, I don’t know whether I should use these two commands, as I assume that the bootstrap command should already give the pipeline permission to do whatever it needs in the prod account. Second, if I should use websiteBucket.grantPut(pipeline.role), then why it doesn’t work.

2

Answers


  1. If I got it right you are using 111111 as your tools account and also have the pipeline deployed in that account. That is why websiteBucket.grantPut(pipeline.role) only adds the permissions in account 111111 as the pipeline only gets deployed into 111111. And the error message you are getting hints to a missing trust relationship between 111111 and 222222. Maybe check that one first.

    Login or Signup to reply.
  2. It looks like you may have a misunderstanding with the pipeline role. It is used only to create resources in the pipeline, and to assume the deployment role in the target account. The deployment role in turn assumes the execution role, which must have permission to create/modify resources in the prod account.

    If you have used the bootstrap commands you mention above, then the execution role will have AdministratorAccess in the prod account. Normally that would allow it to do anything.

    In your case the execution role will be:
    cdk-hnb659fds-cfn-exec-role-222222-us-east-1

    What’s happening here is the S3 bucket policy does not allow the execution role to put objects. It looks like the bucket is created by CDK in a different stack – you will need to modify it to allow access from the prod execution role.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search