AWS Cdk v2 reading exported CloudFormation Stack Outputs

In CloudFormation information between stacks are shared as exported outputs within an AWS account and region. A output is created as CfnOutput object and when a exportName property is set, the output is exported.

An output can be read from another stacks with the Fn. functions (importValue() or importListValue()).

Stack Outputs

NOTE:
Do not share passwords, keys or secrets this way

StackOne

StackOne defines a variable to share with other stacks as output. This can be an ARN, a table name or something else.

File: StackOne/lib/stack_one-stack.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { Stack, StackProps, CfnOutput } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as lambda from "aws-cdk-lib/aws-lambda";

export class StackOneStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const someVar = "aValueToShare";

    new lambda.Function(this, "One", {
      runtime: lambda.Runtime.NODEJS_14_X,
      code: lambda.Code.fromAsset('src/lambda'),
      handler: "one.handler",
      environment: {
        SOMEVAR: someVar,
      },
    });

    new CfnOutput(this, "SomeVar", {
      value: someVar,
      exportName: "SomeVar",
      description: "Description of the 'SomeVar'"} );

  }
}

Line 9

defines a sample variable someVar.

Lines 20 - 23

create the CloudFormation Output SomeVar which other stacks can read with the name/id (exportName: "SomeVar").

StackTwo

StackTwo reads the CloudFormation Output SomeVar.

File: StackTwo/lib/stack_two-stack.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import { Stack, StackProps, Fn } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as lambda from "aws-cdk-lib/aws-lambda";

export class StackTwoStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const someVar = Fn.importValue("SomeVar");

    new lambda.Function(this, "Two", {
      runtime: lambda.Runtime.NODEJS_14_X,
      code: lambda.Code.fromAsset('src/lambda'),
      handler: "two.handler",
      environment: {
        SOMEVAR: someVar,
      },
    });
  }
}

Line 9

read the CfOutput with the name/id SomeVar.

Lines 18 - 25

use the imported value and use it to a environment variable SOMEVAR to make it avail to the lambda.

How to test

build and deploy the two stacks.

Deploy StackOne

$ cd StackOne
$ cd src/lambda/
$ npm install
$ cd ../..
$ npm install
$ npm run build
$ cdk deploy

In the logs of the deployment command are the CloudFormation ‘Outputs’ listed and ‘SomeVar’ (StackOneStack.SomeVar) is listed here.

.
.
Outputs:
StackOneStack.SomeVar = aValueToShare
Stack ARN:
arn:aws:cloudformation:re-regionx-1:123456789012:stack/StackOneStack/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Deploy StackTwo

$ cd StackTwo
$ cd src/lambda/
$ npm install
$ cd ../..
$ npm install
$ npm run build
$ cdk deploy

In the generated AWS SAM template of the stack the "Fn::ImportValue" is used to import the variable ‘SomeVar’.

more cdk.out/StackTwoStack.template.json 
.
.
    "Environment": {
     "Variables": {
      "SOMEVAR": {
       "Fn::ImportValue": "SomeVar"
      }
     }
    },
.
.

To check if the lambda is able to read the variable with the imported value, invoke the lambda ‘Two’.

$ aws lambda invoke --function-name StackTwoStack-TwoXXXXXXXX-XXXXXXXXXXXX response.json
$ cat response.json
{"statusCode":200,"body":"SomeVar: aValueToShare}

‘SomeVar’ must contain ‘aValueToShare’ as defined in StackOne.

Cleanup

Remove both stacks.

Delete StackOne

Delete the StackOne.

$ cd StackOne
$ cdk destroy

Delete StackTwo

Delete the StackTwo.

$ cd StackTwo
$ cdk destroy

Requires

Tool Version See
AWS CDK v2 >= 2.23.0 Tools
NodeJs >= 14.19.0 Tools
npm >= 8.8.0 Tools
TypeScript >= 3.9.7 TypeScript ↱