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

Allow Dynamic References for Secure Values in Custom Resources

Open fimbulvetr opened this issue 6 years ago • 8 comments

Scope of request

Currently, you can use Dynamic References for Secure Values, i.e. {{resolve:ssm-secure:IAMUserPassword:10}} in most places. However, it is not possible to use them as parameters (read: arguments) to a Custom Resource.

This is documented here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-ssm-secure-strings

Under Addition Considerations:

  • Dynamic references for secure values, such as ssm-secure and secretsmanager, are not currently supported in custom resources.

Samples:

AWSTemplateFormatVersion: "2010-09-09"
Resources: 
  MyFrontEndTest: 
    Type: "Custom::PingTester"
    Version: "1.0"
    Properties: 
      ServiceToken: "arn:aws:sns:us-east-1:84969EXAMPLE:CRTest"
      Password: {{resolve:ssm-secure:IAMUserPassword:10}} 
Outputs: 
  CustomResourceAttribute1: 
    Value: 
      Fn::GetAtt: 
        - MyFrontEndTest
        - responseKey1
  CustomResourceAttribute2: 
    Value: 
      Fn::GetAtt: 
        - MyFrontEndTest
        - responseKey2

Expected Behavior:

We should be allowed to use a dynamic reference for secure values on custom resources.

Helpful links:

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-ssm-secure-strings https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cfn-customresource.html

Category:

Compute, Security

fimbulvetr avatar Jan 15 '20 16:01 fimbulvetr

we don’t have any plans to invest in this currently, so for now we’d suggest migrating over to resource providers

TheDanBlanco avatar Jan 21 '20 18:01 TheDanBlanco

@TheDanBlanco

Hello. Why are there no plans to do so ?

I created my own resource provider since but then, the problem you see is, we do not have the possibility to create private resources that will have VPC access.

As per your support team, even if we had a Cloudformation VPC endpoint to provide access in both ways (such as what's required for Glue to have access to in-VPC resources), these private resources created through resource providers do not seem to be able to be set to reach resources in-VPC.

I have in the meantime created a tiny lib that will allow the functions (lambda) to parse the resolve string and behave in the way one would expect CFN to do so, but that is just one more thing for people to have to think about when packaging their applications.

EDIT: I have written the following lib https://pypi.org/project/aws-cfn-custom-resource-resolve-parser/ which allows users to keep writing {{resolve:secretsmanager}} in the same way, so all that's needed is to pre-parse the string with it before passing it onto the rest of the lambda function.

JohnPreston avatar Apr 05 '21 08:04 JohnPreston

@aws-cdk/aws-eks / Cluster / addManifest(id, ...manifest)

This will create a Custom Resource. When using this to add a file that contains a password it means that we cannot use secretsManager to store that password and instead have to add it into the raw config file in our code repository.

So please let this be used for Custom Resources so that we no longer have to do this.

Thanks

gburke-ppb avatar May 28 '21 14:05 gburke-ppb

I know this issue is fairly old at this point but was wondering if anyone has an update regarding this. @gburke-ppb did you end up finding a workaround? 😄 Any information is greatly appreciated!

ckatsaras-godaddy avatar Jan 31 '23 18:01 ckatsaras-godaddy

@ckatsaras-godaddy I had similar issue and just implemented it in my custom resource under https://github.com/SodaDev/sns-platform-application

SodaDev avatar Feb 02 '23 08:02 SodaDev

A workaround for this is to resolve it first with another custom resource. Just keep in mind that due to the nature of custom resouces this will mean the secret is exposed in the CloudWatch logs for the custom resource (although not the the CloudFormation template).

import SecretsManager from "aws-cdk-lib/aws-secretsmanager";
import CdkCustomResources from 'aws-cdk-lib/custom-resources';

// The secret to be resolved
const mySecret = new SecretsManager.Secret(scope, "MySecureSecret", {
  generateSecretString: {
    passwordLength: 32,
    excludePunctuation: true,
    includeSpace: false,
    requireEachIncludedType: true
  },
  removalPolicy: CDK.RemovalPolicy.DESTROY,
});


// An annoying limitation of CloudFormation is that it won't resolve dynamic references for secrets when 
// used as a parameter to a custom resource. To get around this we manually resolve it with another custom 
// resource. Note this won't result in the secret being exposed in CloudFormation templates but it will
// be visible in the CloudWatch logs of the custom resource lambda. It's up to you to decide if this is acceptable or not.
// https://github.com/aws-cloudformation/cloudformation-coverage-roadmap/issues/341
const resolveMySecret = new CdkCustomResources.AwsCustomResource(this, "GetSecret", {
  // There's no real benefit of fetching the latest sdk our case for the cost of a longer execution time
  installLatestAwsSdk: false, 
  // Since there's no onCreate, onUpdate will be called for CREATE events
  onUpdate: { 
    service: '@aws-sdk/client-secrets-manager',
    action: 'getSecretValue',
    parameters: {
      SecretId: mySecret.secretArn,
    },
    // We include a timestamp in the physicalResourceId to ensure we fetch the latest secret value on every update
    physicalResourceId: CdkCustomResources.PhysicalResourceId.of(`GetSecret-${Date.now()}`),
  },
  policy: CdkCustomResources.AwsCustomResourcePolicy.fromSdkCalls({
    resources: [mySecret.secretArn],
  }),
});

// Example custom resource were the secret is used
new CdkCustomResources.AwsCustomResource(this, "ExampleCustomResource", {
  onUpdate: {
    service: '@aws-sdk/client-cloudfront-keyvaluestore',
    action: 'putKey',
    parameters: {
      KvsARN: kvsArn,
      Key: key,
      Value: resolveMySecret.getResponseField('SecretString'),
      IfMatch: etag,
    },
    physicalResourceId: CdkCustomResources.PhysicalResourceId.of(`${kvStoreId}-${key}`),
  },
  policy: CdkCustomResources.AwsCustomResourcePolicy.fromSdkCalls({
    resources: [kvsArn],
  }),
});

callumgare avatar Oct 29 '25 06:10 callumgare

Disappointing this is still not covered. Real practical limitations w/ CDK

BwL1289 avatar Nov 21 '25 16:11 BwL1289

Whats worse, AFAICT, the returned value from the workaround CR is a json string so you can't access fields in the mapping as you normally would with dot notation (i.e. SecretString.<your_value>).

This makes the workaround extremely brittle.

BwL1289 avatar Nov 21 '25 18:11 BwL1289