aws-cdk: Stack/BuildPipeline/ArtifactsBucketEncryptionKeyAlias fails to get recreated when cdk deploy follows cd destroy

A .NET CDK 1.9 (and then 1.10) project that builds a CodePipeline with CodeCommit and CodeBuild stages, fails when cdk deploy is run after cdk destroy with the error messages saying “XxxxxxxStack/BuildPipeline/ArtifactsBucketEncryptionKeyAlias (BuildPipelineArtifactsBucketEncryptionKeyAliasXXXXXXXX) alias/codepipeline-somepipelineb5eb558e already exists” Since a KMS key can only be deleted only after at least 7 days later, the region where this error happens makes the region unusable for the CDK project for at least 7 days!

Reproduction Steps

  1. Build a stack including CodePipeline containing CodeCommit and CodeBuild. Deploy with cdk deploy
  2. Trigger a build that will check out source into an artifact.
  3. Run cdk destroy.
  4. Run cdk deploy again. Observe error above"
  5. Try to delete or rename the KMS key alias - cannot be done as it’s not meant to be. KMS key can be scheduled to be deleted in nor earlier than 7 days.

Error Log

XxxxxxxStack/BuildPipeline/ArtifactsBucketEncryptionKeyAlias (BuildPipelineArtifactsBucketEncryptionKeyAliasXXXXXXXX) alias/codepipeline-somepipelineb5eb558e already exists

Environment

  • CLI Version : 1.10
  • Framework Version: 1.10
  • OS : Windows 10
  • Language : C#/.NET

Other

19/28 | 5:39:18 PM | CREATE_FAILED | AWS::KMS::Alias | CicdInfraAsCodeStack/BuildPipeline/ArtifactsBucketEncryptionKeyAlias (BuildPipelineA rtifactsBucketEncryptionKeyAlias68E67B02) alias/codepipeline-cicdinfraascodestackbuildpipelineb5eb558e already exists
new Alias (C:\Users\username\AppData\Local\Temp\jsii-kernel-AAuzoS\node_modules@aws-cdk\aws-kms\lib\alias.js:69:26)
_ new Pipeline (C:\Users\username\AppData\Local\Temp\jsii-kernel-AAuzoS\node_modules@aws-cdk\aws-codepipeline\lib\pipeline.js:86:13)
_ C:\Users\username\AppData\Local\Temp\dcqv0cxm.fwo\jsii-runtime.js:6798:49
_ Kernel._wrapSandboxCode (C:\Users\username\AppData\Local\Temp\dcqv0cxm.fwo\jsii-runtime.js:7250:20)
_ Kernel._create (C:\Users\username\AppData\Local\Temp\dcqv0cxm.fwo\jsii-runtime.js:6798:26)
_ Kernel.create (C:\Users\username\AppData\Local\Temp\dcqv0cxm.fwo\jsii-runtime.js:6552:21)
_ KernelHost.processRequest (C:\Users\username\AppData\Local\Temp\dcqv0cxm.fwo\jsii-runtime.js:6327:28)
_ KernelHost.run (C:\Users\username\AppData\Local\Temp\dcqv0cxm.fwo\jsii-runtime.js:6270:14)
_ Immediate._onImmediate (C:\Users\username\AppData\Local\Temp\dcqv0cxm.fwo\jsii-runtime.js:6273:37)
_ processImmediate (internal/timers.js:439:21)


This is 🐛 Bug Report

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 22 (12 by maintainers)

Commits related to this issue

Most upvoted comments

And also, this is a new kind of statefulness which requires deployment-time manual steps. It is also a backwards-incompatible feature released in a minor version, which isn’t ideal for a module marked stable. You changed the default, mind you.

Doesn’t the same kind of question of aliases-for-clarity apply to all other places where CDK defaults to using KMS encryption? Why just with pipelines? To my mind consistency across the CDK is more important. On the usability level it’s good to remember that many of us deploy and tear down pipelines several times a day – it’s a very common occurrence.

This is a case of CDK trying to be too clever, thereby shooting its users in the foot. What you have done is prompt people to use unencrypted buckets because the abstractions you more or less randomly have added now make pipelines too cumbersome to use. We suddenly find us having painted ourselves into a corner without knowing it, as we now have aliases which need special care. That’s a breaking change we didn’t ask for, and in a minor release.

I think you should bring up the issue of reverting the alias feature with the team. It needs to be rethought, and there ought to be a discussion about the principles of CDK’s use of extra abstraction in general.

However. If this situation indeed isn’t a bug but a feature requiring manual steps – without which a redeploy after a destroy will fail – then this forces certain architectural decisions when using CDK. That’s less ideal in my opinion; CDK should widen, not narrow down our options.

In my particular use case, I will have to resort to either using manually managed KMS keys (and set up procedures around them with devs and ops and write appropriate installation and maintenance sections in the relevant runbooks), a non-encrypted bucket, or a custom resource which handles the existence of the alias.

Can you explain why CDK narrows your options here? Why not use something like this in your code:

const bucket = new s3.Bucket(this, 'ArtifactBucket', {
  encryption: s3.BucketEncryption.KMS, // encrypted bucket with a key, _without_ an alias! 
  // ...
});

const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
  artifactBucket: bucket,
  // ...
});

or even this:

// no alias, key destroyed on `cdk destroy`
const key = new kms.Key(this, 'Key', {
  removalPolicy: RemovalPolicy.DESTROY,
  // ...
});
// bucket destroyed on `cdk destroy`, but only if it's empty!
const bucket = new s3.Bucket(this, 'ArtifactBucket', {
  encryptionKey: key,
  removalPolicy: RemovalPolicy.DESTROY,
  // ...
});
const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
  artifactBucket: bucket,
  // ...
});

The issue is not whether what you’ve done makes sense. The issue is consistency across the CDK, backward compatibility, introducing breaking changes in minor versions, and increasing the learning curve of CDK. It’s the CDK team’s cavalier attitude towards semantic versioning. It’s not understanding that adding abstractions in an opaque way to projects which already are underway whilst at the same time disregarding the conventions of semantic versioning makes professional projects considerably more difficult to manage. It’s not understanding that how the CDK team currently does things will lead to rejection of CDK as a tool in any kind of controlled environment.

I’ll explain our use case in detail privately to you and Elad – security concerns prevent me from doing so publicly – for it is important that you understand who we are and where we’re coming from.

Thanks!

Hey @vgribok ,

thanks for opening the issue. I think there’s a few things you can do here:

  1. Remove the Alias from the AWS CLI. I’m pretty sure an Alias can be removed without removing the underlying Key (only the Key has the 7 day grace period).
  2. The Key is there only by default. You can pass an explicit Bucket when creating the Pipeline, one that doesn’t have a Key (or a different Key, possibly with a different Alias):
const myArtifactBucket = new s3.Bucket(this, 'Bucket', {
  // possibly pass a Key, maybe with an Alias, here?
  // ...
});

const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
  artifactBucket: myArtifactBucket.
  // ...
});

Let me know if this helps!

Thanks, Adam