aws / aws/aws-cdk

(secrets): How do we force Secret resolution in a particular scope?

Open
#28,845 3 comments 0 reactions 0 assignees View on GitHub
@aws-cdk/aws-secretsmanager bug p3
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
2d 3h
Merged PRs (30d)
83

Description

### Describe the bug

Ref: https://cdk-dev.slack.com/archives/C018XT6REKT/p1706125503162629

I want to resolve a secret (`{{resolve:secretsmanager...}}` within the context of a parent `Stack`, and pass the parameter through to a `NestedStack`. This will allow the nested stack to use the parameter in `Custom::xxx` resources. This is a pattern we have in many of our legacy YAML based CloudFOrmation stacks and it works well.

When I try to do this, CDK seems to do the resolution in the nested stack itself.. this resolution then fails, and the custom resource will not work. It seems odd to me that a `Secret` would be resolved (turned into `{{resolve:...}}` in ANY context other than the scope passed to it.

### Expected Behavior

I expect the resolution to occur in the parent stack where I have passed the scope in.

### Current Behavior

It is resolved in the nested stack.

### Reproduction Steps

```typescript
# stack.ts
/** @format */

import { CustomResource, NestedStack, NestedStackProps, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Secret } from 'aws-cdk-lib/aws-secretsmanager';

export interface AppStackProps extends NestedStackProps {
readonly apikey: string;
}

export class ExampleStack extends Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
new AppStack(this, 'appStack', {
apikey: Secret.fromSecretNameV2(this, 'ApiKey', '/secret').secretValue.toString(),
});
}
}

export class AppStack extends NestedStack {
constructor(scope: Construct, id: string, props: AppStackProps) {
super(scope, id);

new CustomResource(this, 'Custom::thingy', {
serviceToken: 'arn:to:lambda',
properties: {
token: props.apikey,
},
});
}
}
```

## Generate it...
```
yarn cdk synth
```

## Check out the output:

```json
# template.json
{
"Resources": {
"appStackNestedStackappStackNestedStackResourceA44C89FF": {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": {
"Fn::Join": [
"",
[
"https://s3.us-west-2.",
{
"Ref": "AWS::URLSuffix"
},
"/cdk-hnb659fds-assets-XXXXX-us-west-2/aa703b1fd367d9aecc9683745cac0b97d90123b2d2a96a4014499c95009bf223.json"
]
]
}
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete",
"Metadata": {
...
}
},
"CDKMetadata": {
"Type": "AWS::CDK::Metadata",
"Properties": { },
"Metadata": {
"aws:cdk:path": "Stage/ExampleStack/CDKMetadata/Default"
}
}
},
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
}
```

```json
# nested.template.json
{
"Resources": {
"Customthingy": {
"Type": "AWS::CloudFormation::CustomResource",
"Properties": {
"ServiceToken": "arn:to:lambda",
"token": {
"Fn::Join": [
"",
[
"{{resolve:secretsmanager:arn:",
{
"Ref": "AWS::Partition"
},
":secretsmanager:us-west-2:XXXXX:secret:/secret:SecretString:::}}"
]
]
}
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete",
"Metadata": {
"aws:cdk:path": "Stage/ExampleStack/appStack/Custom::thingy/Default"
}
},
"CDKMetadata": {
"Type": "AWS::CDK::Metadata",
"Properties": { },
"Metadata": {
"aws:cdk:path": "Stage/ExampleStack/appStack/CDKMetadata/Default"
}
}
}
```

### Possible Solution

_No response_

### Additional Information/Context

_No response_

### CDK CLI Version

2.115.0

### Framework Version

_No response_

### Node.js Version

18

### OS

osx

### Language

TypeScript

### Language Version

_No response_

### Other information

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with the TypeScript reproduction in stack.ts and run yarn cdk synth to compare template.json with nested.template.json. Trace how the Secret value is assigned across ExampleStack and AppStack, then use the generated templates to verify that resolution occurs in the parent stack as requested.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
cloud, infrastructure
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.