5

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?

Brian Anderson
  • 621
  • 7
  • 22

2 Answers2

8

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.

fedonev
  • 20,327
  • 2
  • 25
  • 34
  • Thank you for your help! I was trying to get the entire JSON object, instead of each individual secret. Once I switched to get each secret separately, then it worked! – Brian Anderson Mar 07 '22 at 20:42
2

Use secretValue.unsafeUnwrap() , this is the only way to get it working with CDK. Otherwise it will fail, since the secret data is available in generated yaml or json file which is used by the cdk ... in other words cloud formation.

Ion Scorobogaci
  • 147
  • 2
  • 5