cloudformation-coverage-roadmap icon indicating copy to clipboard operation
cloudformation-coverage-roadmap copied to clipboard

Updating AWS::CloudFront::PublicKey results in BadRequest error

Open ArielPrevu3D opened this issue 3 years ago • 7 comments

Name of the resource

AWS::CloudFront::PublicKey

Resource Name

No response

Issue Description

Updating the key value of a AWS::CloudFront::PublicKey resource results in a BadRequest error instead of recreating the physical resource. This is because they key value of a CloudFront public key is immutable and CloudFormation doesn't handle the edge case.

Expected Behavior

CloudFormation should detect that the encoded material of the AWS::CloudFront::PublicKey resource changed and recreate the PublicKey physical resource.

Observed Behavior

Failed resources:
 05:01:21 | UPDATE_FAILED        | AWS::CloudFront::PublicKey                      | gatewayLambda/AssetsCFPublicKey (gatewayLambdaAssetsCFPublicKeyXXXXXXXX) Resource handler returned message: "Invalid request provided: AWS::CloudFront::PublicKey" (RequestToken: xxxxxxxx-xxxxx-xxxxx, HandlerErrorCode: InvalidRequest)
        new PublicKey (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\node_modules\@aws-cdk\aws-cloudfront\lib\public-key.ts:42:22)
        \_ new GatewayConstruct (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\lib\constructs\gateway.construct.ts:244:22)
        \_ new BackendStack (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\lib\stack.ts:47:21)
        \_ Object.<anonymous> (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\bin\iac.ts:5:1)
        \_ Module._compile (internal/modules/cjs/loader.js:1063:30)
        \_ Module.m._compile (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\node_modules\ts-node\src\index.ts:1056:23)
        \_ Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
        \_ Object.require.extensions.<computed> [as .ts] (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\node_modules\ts-node\src\index.ts:1059:12)     
        \_ Function.Module._load (internal/modules/cjs/loader.js:769:14)
        \_ Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
        \_ main (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\node_modules\ts-node\src\bin.ts:198:14)
        \_ Object.<anonymous> (C:\Users\Romain\Documents\1.REPOS\cloud-platform\backend\node_modules\ts-node\src\bin.ts:288:3)
        \_ Module._compile (internal/modules/cjs/loader.js:1063:30)
        \_ Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
        \_ Module.load (internal/modules/cjs/loader.js:928:32)
        \_ Function.Module._load (internal/modules/cjs/loader.js:769:14)
        \_ Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)

From CloudTrail logs

{
    "errorCode": "CannotChangeImmutablePublicKeyFields",
    "errorMessage": "You cannot modify encoded material and name of a public key once created.", 
}

Test Cases

  1. Create a template with a AWS::CloudFront::PublicKey resource.
  2. Deploy successfully.
  3. Update the PublicKeyConfig.EncodedKey value.
  4. Attempt a deployment and the error will occur.

Other Details

Using CDK 1.124.0

ArielPrevu3D avatar Sep 22 '21 17:09 ArielPrevu3D

As mentioned in the API documentation : UpdatePublicKey UpdatePublicKey action lets you update just the Comment field. The values EncodedKey and Name are immutable, and cannot be updated once created. To update the Key or the Name, a new PublicKey must be created using CreatePublicKey and use it.

gangavab avatar Nov 02 '21 04:11 gangavab

As mentioned in the API documentation : UpdatePublicKey UpdatePublicKey action lets you update just the Comment field. The values EncodedKey and Name are immutable, and cannot be updated once created. To update the Key or the Name, a new PublicKey must be created using CreatePublicKey and use it.

This is true about the AWS API, but with CloudFormation a construct's physical resource should be replaced when doing so is necessary. For example, renaming a Lambda function or changing an EC2 instance's AZ won't result in a 400 from CloudFormation's internal API requests. Also, a user of CloudFormation doesn't have any control over the API calls themselves, it is CloudFormation's responsibility to make proper use of the API.

To get around this, a CloudFormation user must use a custom construct or mutate the logical ID manually to force replacement of the key. This is not common behavior in CloudFormation.

ArielPrevu3D avatar Nov 02 '21 14:11 ArielPrevu3D

Have you found a good way to mutate within CloudFormation?

tinducvo avatar Jan 22 '22 16:01 tinducvo

Have you found a good way to mutate within CloudFormation?

This is trivial if you're using CDK. I ended up adding a hash of the key to the ID of the PublicKey resource. This way, if the key value changes, a new key is created and the old one is delete. I don't know enough about vanilla CloudFormation to know if there's an easy workaround.

ArielPrevu3D avatar Jan 24 '22 21:01 ArielPrevu3D

This bit me in the ass today, too. I described the problem and available workarounds here: You’re getting "Invalid request provided: AWS::CloudFront::PublicKey" because CloudFront Public Keys are immutable. I wish CloudFormation provided a cleaner way to modify these public keys.

dltj avatar Feb 12 '22 03:02 dltj

This is indeed an unexpected and cumbersome issue to tackle for us too. I do understand that these keys are cached by your loadbalancers on each edege location, however having to rotate them with a limit of up to 10 public keys [1] for each account is a pita. It actually leads us to create a new AWS account for each CloudFront distribution and creates heavy/no-sense friction on configuration management.

[1] https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html

emanuelelevo avatar Jul 13 '22 16:07 emanuelelevo

+1 please fix this so that we can automate the rotation of trustedKeyGroup keys using cloudformation template in Type: AWS::CloudFront::PublicKey

thanks @dltj for your blog that helped me catch that undescriptive cloudformation error

jacov avatar Jul 24 '23 21:07 jacov