Home > OS >  AWS SecretsManager value won't resolve
AWS SecretsManager value won't resolve

Time:03-07

I'm using aws-cdk-lib (2.13.0). Here's a snippet of my code:

import { App, Stack } from 'aws-cdk-lib';
import { Secret } from 'aws-cdk-lib/aws-secretsmanager';

export class CognitoStack extends Stack {
  constructor(scope: App) {
    super(scope, 'cognito');

    const secret = this.getSecret('google');
    console.log({ secret });
  }

  public getSecret(path: string) {
    const secret = Secret.fromSecretNameV2(this, `Secret${path}`, path);
    console.log({ path, secret, secretArn: secret.secretArn, string: secret.secretValue.toString() });
    return secret.secretValue.toJSON();
  }
}

The resulting logs look like this:

{
  path: 'google',
  secret: <ref *1> SecretBase {
    node: Node {
      host: [Circular *1],
      _locked: false,
      _children: {},
      _context: {},
      _metadata: [],
      _dependencies: Set(0) {},
      _validations: [Array],
      id: 'Secretgoogle',
      scope: [CognitoStack]
    },
    stack: CognitoStack {
      node: [Node],
      _missingContext: [],
      _stackDependencies: {},
      templateOptions: {},
      _logicalIds: [LogicalIDs],
      account: '${Token[AWS.AccountId.4]}',
      region: '${Token[AWS.Region.8]}',
      environment: 'aws://unknown-account/unknown-region',
      terminationProtection: undefined,
      _stackName: 'cognito',
      tags: [TagManager],
      artifactId: 'cognito',
      templateFile: 'cognito.template.json',
      _versionReportingEnabled: true,
      synthesizer: [DefaultStackSynthesizer],
      [Symbol(@aws-cdk/core.DependableTrait)]: [Object]
    },
    env: {
      account: '${Token[AWS.AccountId.4]}',
      region: '${Token[AWS.Region.8]}'
    },
    _physicalName: undefined,
    _allowCrossEnvironment: false,
    physicalName: '${Token[TOKEN.332]}',
    encryptionKey: undefined,
    secretName: 'google',
    secretArn: 'arn:${Token[AWS.Partition.7]}:secretsmanager:${Token[AWS.Region.8]}:${Token[AWS.AccountId.4]}:secret:google',
    autoCreatePolicy: false,
    [Symbol(@aws-cdk/core.DependableTrait)]: { dependencyRoots: [Array] }
  },
  secretArn: 'arn:${Token[AWS.Partition.7]}:secretsmanager:${Token[AWS.Region.8]}:${Token[AWS.AccountId.4]}:secret:google',
  string: '${Token[TOKEN.333]}'
}
{ secret: '<unresolved-token>' }

The results of the npx cdk diff sandbox-cognito look like this:

Stack sandbox-cognito
Resources
[~] AWS::Cognito::UserPoolIdentityProvider Google GoogleAF1E99FA
 └─ [~] ProviderDetails
     ├─ [-] Removed: .client_id
     └─ [-] Removed: .client_secret

Which means that it is removing the client_id/client_secret that I was able to set manually. Now that I'm trying to load the values from a secret, it is not working.

The problem is that I cannot parse the JSON (notice the <unresolved-token> in the logs. I think that it is not yet resolved, but I'm not sure how to resolve... It's trying parse this string literal: ${Token[TOKEN.333]}, instead of the secret value. How can I get the results of the secret string?

CodePudding user response:

This defeats the purpose of Secrets Manager, is not secure, and is therefore not supported. The value will be resolved at deploy time, not at synth time.

You should think about removing this requirement to resolve the value at synth time.

CodePudding user response:

Import your existing secret as a SecretValue. Pass it to the clientSecret:string prop using the .toString() method.

// Existing secret as SecretValue.  Or use Secret.fromSecretNameV2.
const secretVal = cdk.SecretValue.secretsManager('GoogleSecrets', {
  jsonField: 'client-secret',
});

new cognito.UserPoolIdentityProviderGoogle(this, 'GoogleProvider', {
  userPool,
  // creates a dynamic reference which resolves to the actual secret value at deploy-time
  clientSecret: secretVal.toString(),
  clientId: 'my-id',
});

Explanation

SecretValue.toString() "resolves" to different values during the lifecycle: When you console.log it, you get an (useless) opaque placeholder Token value like ${Token[TOKEN.198]}. At synth-time CDK renders a CloudFormation dynamic reference in the template:

//my-stack.template.json
{"client_secret": "{{resolve:secretsmanager:arn:aws:secretsmanager:us-east-1:123456789012:secret:GoogleSecrets:SecretString:client-secret::}}"}

At deploy-time, CloudFormation "resolves" the actual secret value from the dynamic reference.

The important takeaway is that the actual secret value is never exposed to your local environment or the template artefacts.

  • Related