How to export and import stack output values in CDK?

Zhiyuan Li
3 min readMar 30, 2021

Summary

In CloudFormation, to share information between stack, it is normal to export a stack’s output values, other stacks that are in the same AWS account and region can import the exported values. In CDK, we can do the same by using `CfnOutput` and `Fn.importValue` from `core` module.

Resolution

In CloudFormation, to export a stack’s output value, we use the `Export` field in the `Output` section of the stack’s template. To import those values, we use the `Fn::ImportValue` function in the template for the other stacks.

In the context of CDK, a CDK stack will be synthesized to an AWS CloudFormation Template. To share information between CDK stacks using the low-level CloudFormation features, we need to do following:

1. Import `core` module. The module package was named `aws_cdk.core` in Typescript or Javascript; `aws_cdk.core` in Python; `software.amazon.awscdk.core` in Java; `Amazon.CDK` in DOTNET.

Normally, this step is done by CDK CLI when we run `cdk init` to create a CDK project.

2. Define the resources in the stack

3. Create a `CfnOutput` object, specify the `value` and `exportName`.

4. In other stacks that need to import this output value, pass the value of `exportName` to `Fn.importValue()` from `core` module.

5. Once we have the imported variable, we normally need to use static method `fromXXX` to import existing resources to the importing stacks.

For example, to import a security group, use `fromSecurityGroupId()`; to import an IAM role, use `fromRoleArn()`.

Do note that, using this low-level CloudFormation export / import feature to share information between CDK stacks is not a CDK-native solution, a more CDK-native solution is to define custom constructs and share information through constructs, however, this export / import solution allow customers who familiar with CloudFormation workflow to access low-level CloudFormation features when needed.

Example

Walk through a real world Typescript scenario, I created two stack: IamStack as exporting stack, and Ec2Stack as importing stack. In IamStack, it creates a instance role and then export the role’s ARN, once IamStack got created, I created another stack Ec2Stack which importing the role’s ARN from IamStack. See the attached project bundle for reference.

Below is the code of IamStack (iam.ts):

import * as cdk from '@aws-cdk/core';
import * as iam from '@aws-cdk/aws-iam';
export class IamStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// create an IAM Role for ec2 instance
const ec2Role = new iam.Role(this, "ec2Role", {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
});
// create an output object which defined value and exportName
new cdk.CfnOutput(this, "ec2RoleArn", {
value: ec2Role.roleArn,
exportName: "ec2RoleArn",
});
}
}

Below is the code of Ec2Stack (ec2.ts):

import * as cdk from '@aws-cdk/core';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
export class Ec2Stack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// import the default vpc
const vpc = ec2.Vpc.fromLookup(this, 'vpc', {
isDefault: true,
});
// import the ec2 instance role from exporting stack `IamStack`
const ec2Role = iam.Role.fromRoleArn(
this, 'ec2Role', cdk.Fn.importValue('ec2RoleArn'));

// use the importing role for an ec2 instance
new ec2.Instance(this, 'testInstance', {
machineImage: new ec2.AmazonLinuxImage(),
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T3,
ec2.InstanceSize.NANO
),
vpc,
role: ec2Role, // use the imported role
});
}
}

Below is the code of CDK App entry point:

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { IamStack } from '../lib/iam';
import { Ec2Stack } from '../lib/ec2';
const app = new cdk.App();new IamStack(app, 'IamStack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});
new Ec2Stack(app, 'Ec2Stack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});

Synthesized CFN template sippet for IamStack:

Outputs:
ec2RoleArn:
Value:
Fn::GetAtt:
- ec2Role38AB65C0
- Arn

Synthesized CFN template sippet for Ec2Stack:

testInstanceInstanceProfile70854DE1:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- Fn::Select:
- 1
- Fn::Split:
- /
- Fn::Select:
- 5
- Fn::Split:
- ":"
- Fn::ImportValue: ec2RoleArn

Reference

[1] core module

--

--

Zhiyuan Li

I blog about Cloud, DevOps, Cybersecurity. Opinions are my own.