Allow Dynamic References for Secure Values in Custom Resources
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
we don’t have any plans to invest in this currently, so for now we’d suggest migrating over to resource providers
@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.
@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
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 I had similar issue and just implemented it in my custom resource under https://github.com/SodaDev/sns-platform-application
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],
}),
});
Disappointing this is still not covered. Real practical limitations w/ CDK
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.