Reference: https://repost.aws/knowledge-center/cdk-cross-stack-reference
- Create a project and invoke cdk init in an empty directory:
mkdir my-project
cd my-project
cdk init --language typescript
- Rename file from
my-project-stack.ts
tocdk-producer-stack.ts
:
mv lib/my-project-stack.ts lib/cdk-producer-stack.ts
- Import aws library, add the below:
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
- Define a stack and set a property for the Amazon VPC (for this example producerStack):
export class producerStack extends cdk.Stack {
public readonly vpc: ec2.IVpc;
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
this.vpc = new ec2.Vpc(this, 'cdk-ss-vpc', {
maxAzs: 2,
natGateways: 0,
});
}
}
- Go to
bin/my-project.ts
, and add below:
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { producerStack } from '../lib/cdk-producer-stack';
const env = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }
const app = new cdk.App();
const producer_stack = new producerStack(app, 'cdk-producer-stack', {
env: env,
});
cdk.Tags.of(producer_stack).add('auto-delete', 'no');
cdk.Tags.of(producer_stack).add('managedBy', 'cdk');
cdk.Tags.of(producer_stack).add('environment', 'dev');
- Run the commands:
cdk ls
cdk deploy --all
- Create a new file called:
cdk-consumer-stack.ts
in lib/:
touch lib/cdk-consumer-stack.ts
- Import aws library, add the below:
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
- Export an interface called consumerStackProps:
export interface consumerStackProps extends cdk.StackProps {
vpc: ec2.IVpc;
}
- Define a consumer stack:
export class consumerStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: consumerStackProps) {
super(scope, id, props);
- Define a vpc and security group by adding below:
const vpc = props.vpc;
const SecurityGroup = new ec2.SecurityGroup(this, 'ingressSsh', {
vpc,
allowAllOutbound: true,
});
SecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(22),
'allow SSH access from anywhere',
);
}
}
- Go to
bin/my-project.ts
, and add below:
......
import { consumerStack } from '../lib/cdk-consumer-stack';
const env = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }
const app = new cdk.App();
......
const consumer_stack = new consumerStack(app, 'cdk-consumer-stack', {
env: env,
vpc: producer_stack.vpc,
});
cdk.Tags.of(consumer_stack).add('auto-delete', 'no');
cdk.Tags.of(consumer_stack).add('managedBy', 'cdk');
cdk.Tags.of(consumer_stack).add('environment', 'dev');
-
A Question for audience:
Do I need to add a dependency for the two stacks:question: for example:consumer_stack.addDependency(producer_stack)
. -
Run the commands:
cdk ls
cdk deploy --all
- Create a new file called:
cdk-consumer-ssm-stack.ts
in lib/:
touch lib/cdk-consumer-ssm-stack.ts
- We need to make a few changes in the producer_stack, open
cdk-producer-stack.ts
, and add the following:
...
import * as ssm from "aws-cdk-lib/aws-ssm";
export interface vpcProps extends cdk.StackProps {
readonly vpcName: string;
readonly vpcIdExportPath: string;
}
export class producerStack extends cdk.Stack {
public readonly vpc: ec2.IVpc;
constructor(scope: cdk.App, id: string, props: vpcProps) { // change `props?: cdk.StackProps` to `props: vpcProps`
...
// add :point_down:
const parameter = new ssm.StringParameter(this, 'vpcIdParameter', {
parameterName: props.vpcIdExportPath,
stringValue: this.vpc.vpcId,
});
// add :point_up:
}
}
- Open
bin/my-project.ts
, and add the following:
...
const vpcIdSsmtPath = "/cdk/vpc/cross-stacks-reference/vpcId";
const producer_stack = new producerStack(app, 'cdk-producer-stack', {
env: env,
vpcName: 'cdk-ss-vpc',
vpcIdExportPath: vpcIdSsmtPath,
});
const ssm_consumer_stack = new ssmSgStack(app, 'cdk-consumer-ssm-stack', {
...
- Run the commands:
cdk ls
cdk deploy --all
- Now, open
cdk-consumer-ssm-stack.ts
, and add the below to import aws library,
import * as cdk from 'aws-cdk-lib';
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as ssm from "aws-cdk-lib/aws-ssm";
import { Construct } from 'constructs';
- Export an interface called securityGourpProps:
export interface securityGourpProps extends cdk.StackProps {
readonly vpcIdExportPath: string;
}
- Define a new ssmSgStack stack:
export class ssmSgStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: securityGourpProps) {
super(scope, id, props);
- Define a vpcId using the value store in parameter store:
const vpcId = ssm.StringParameter.valueFromLookup(this, props.vpcIdExportPath);
- As the value is a string, whereas Security Group's vpc is a IVpc, so we need to use FromLookup to convert the string to an Interface. add the below:
const ssVpc = ec2.Vpc.fromLookup(this, 'cdk-ss-vpc',{
vpcId: vpcId,
});
- add the following to use the VPC Interface: ssVpc to create a ssmIgressHttp Security Group:
const SecurityGroup = new ec2.SecurityGroup(this, 'ssmIgressHttp', {
vpc: ssVpc,
allowAllOutbound: true,
});
SecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
'allow HTTP traffic from anywhere',
);
}
}
- open
bin/my-project.ts
, add the following:
...
import { ssmSgStack } from '../lib/cdk-consumer-ssm-stack';
const env = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }
const app = new cdk.App();
const vpcIdSsmtPath = "/cdk/vpc/cross-stacks-reference/vpcId";
const producer_stack = new producerStack(app, 'cdk-producer-stack', {
...
const consumer_stack = new consumerStack(app, 'cdk-consumer-stack', {
...
const ssm_consumer_stack = new ssmSgStack(app, 'cdk-consumer-ssm-stack', {
env: env,
vpcIdExportPath: vpcIdSsmtPath,
});
cdk.Tags.of(consumer_stack).add('auto-delete', 'no');
cdk.Tags.of(consumer_stack).add('managedBy', 'cdk');
cdk.Tags.of(consumer_stack).add('environment', 'dev');
- add stack dependency:
ssm_consumer_stack.addDependency(producer_stack)
- Run the commands:
cdk ls
cdk deploy --all