Skip to content

(aws-secretsmanager): Provide method to obtain a literal (unresolved by CloudFormation) dynamic reference string for a secret's JSON key #34397

Open
@garysassano

Description

@garysassano

Describe the feature

AWS CloudFormation uses the {{resolve:secretsmanager:secret-id:SecretString:json-key}} syntax for dynamic references (docs). When AWS CDK constructs like secret.secretValueFromJson('key').toString() or new CfnDynamicReference(...) are used, CloudFormation typically resolves this reference during stack deployment and substitutes the actual secret value into the target property (e.g., a Lambda environment variable).

However, there are use cases where a tool or service needs to receive the literal dynamic reference string itself (e.g., {{resolve:secretsmanager:my-secret:SecretString:api_key}}), and CloudFormation should not perform this resolution. The receiving tool is expected to parse or handle this raw reference string.

Currently, to achieve this in CDK, one would need to manually construct an Fn::Sub expression with specific escaping to prevent CloudFormation from resolving the dynamic reference. For example:

cdk.Fn.sub(
  '!{{resolve:secretsmanager:\${SecretPlaceholder}:SecretString:jsonKey}}',
  { SecretPlaceholder: secret.secretName } // Or secret.secretArn
)

This is cumbersome, error-prone, and not easily discoverable.

We propose adding a new CDK method to the ISecret interface that simplifies obtaining this literal, unresolved dynamic reference string.

Use Case

A developer is using a specialized tool or a custom configuration agent that expects one of its configuration parameters (passed via a Lambda environment variable, ECS task definition, etc.) to be the literal string {{resolve:secretsmanager:my-prod-secret:SecretString:api_key}}.

If the developer uses the standard mySecret.secretValueFromJson('api_key').toString(), CloudFormation resolves this value, and the tool receives the actual API key (e.g., "12345abcdef"). This is not what the tool expects in this scenario; it needs the raw reference string to perform its own logic.

The developer requires a straightforward CDK mechanism to pass the unevaluated dynamic reference string.

Proposed Solution

Add a new method to the ISecret interface, for example:

export interface ISecret extends IResource {
  // ... existing methods ...

  /**
   * Returns the CloudFormation dynamic reference string for a specific JSON key
   * in the secret, formatted such that CloudFormation will pass it through literally
   * rather than resolving it to the secret's value.
   *
   * This is for use cases where the receiving service or tool, not CloudFormation,
   * needs to process the raw '{{resolve:secretsmanager:...}}' string.
   *
   * Internally, this would typically be implemented using Fn.sub with an escaped
   * dynamic reference pattern, for example:
   *   cdk.Fn.sub('!{{resolve:secretsmanager:\${SecretId}:SecretString:\${JsonKey}}}',
   *              { SecretId: this.secretArn, JsonKey: jsonKey })
   *
   * @param jsonKey The JSON key within the secret (e.g., 'password', 'apiKey').
   * @param options Options for constructing the literal reference.
   */
  literalDynamicReferenceForJsonKey(
    jsonKey: string,
    options?: LiteralDynamicReferenceOptions
  ): string;
}

/**
 * Options for creating a literal dynamic reference.
 */
export interface LiteralDynamicReferenceOptions {
  /**
   * The identifier for the secret (secret-id part of the reference).
   * @default - The ARN of the secret (this.secretArn)
   */
  readonly secretId?: string;

  /**
   * The version stage (version-stage part of the reference).
   * @default - No version stage is included (resolves to AWSCURRENT by CFN if processed by it later).
   */
  readonly versionStage?: string;

  /**
   * The version ID (version-id part of the reference).
   * Cannot be used if versionStage is set.
   * @default - No version ID is included (resolves to AWSCURRENT by CFN if processed by it later).
   */
  readonly versionId?: string;
}

This method would encapsulate the Fn::Sub logic to correctly produce the literal reference string. The secretId in LiteralDynamicReferenceOptions could default to this.secretArn but allow this.secretName or a custom token if needed by the target tool. The versionStage and versionId are optional parts of the dynamic reference syntax.

Other Information

This feature would provide a clean, type-safe, and discoverable way for CDK users to handle scenarios requiring unresolved dynamic references, avoiding manual and potentially incorrect Fn::Sub constructions.

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS CDK Library version (aws-cdk-lib)

2.195.0

AWS CDK CLI version

2.1013.0

Environment details (OS name and version, etc.)

Ubuntu 24.04

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions