How to share a VPC between Stacks in AWS CDK

avatar

Borislav Hadzhiev

Wed May 05 20213 min read

Sharing a VPC between Stacks in AWS CDK #

In this article we are going to look at an example of how to share a VPC between 2 CDK stacks in the same CDK app.

In order to share a VPC between stacks in CDK, we have to:

  1. assign the VPC resource as a class property on stackA
  2. extend the props object of stackB with the VPC type
  3. instantiate stackA so we get access to the VPC resource
  4. instantiate stackB and pass it the VPC resource as a prop
  5. access the VPC on the props object in stackB

Let's start by defining the following 2 stacks:

  1. the VPCStack creates a VPC
  2. the LambdaStack creates a lambda function and places it in the shared VPC
The code for this article is available on GitHub
lib/cdk-starter-stack.ts
import * as ec2 from '@aws-cdk/aws-ec2'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import * as path from 'path'; export class VPCStack extends cdk.Stack { // ๐Ÿ‘‡ set a property for the vpc public readonly vpc: ec2.Vpc; constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); this.vpc = new ec2.Vpc(this, 'my-vpc', { cidr: '10.0.0.0/16', natGateways: 0, subnetConfiguration: [ { name: 'public-subnet-1', subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24, }, ], }); } } // ๐Ÿ‘‡ extend the props interface of LambdaStack interface LambdaStackProps extends cdk.StackProps { vpc: ec2.Vpc; } export class LambdaStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: LambdaStackProps) { super(scope, id, props); const {vpc} = props; cdk.Tags.of(vpc).add('environment', 'development'); cdk.Tags.of(vpc).add('department', 'dpt123'); // ๐Ÿ‘‡ lambda function definition const lambdaFunction = new lambda.Function(this, 'lambda-function', { // ๐Ÿ‘‡ place lambda in shared VPC vpc, allowPublicSubnet: true, runtime: lambda.Runtime.NODEJS_14_X, handler: 'index.main', code: lambda.Code.fromAsset(path.join(__dirname, '/../src/my-lambda')), environment: { // ๐Ÿ‘‡ pass the VPC ID as an environment variable VPC_ID: vpc.vpcId, }, }); } }

Let's go over what we did in the code snippet.

  1. we defined our VPCStack, which creates a VPC. The important part here is that we created a vpc class property and assigned the VPC resource to it. The property can now be accessed on instances of the class.
  2. we extended the default StackProps object with the VPC type
  3. we created our LambdaStack, which references the shared VPC and provisions a lambda function in it
The code for this article is available on GitHub

Let's look at how the classes are instantiated:

bin/cdk-starter.ts
import * as cdk from '@aws-cdk/core'; import {LambdaStack, VPCStack} from '../lib/cdk-starter-stack'; const app = new cdk.App(); const vpcStack = new VPCStack(app, 'vpc-stack', { stackName: 'vpc-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, }); const lambdaStack = new LambdaStack(app, 'lambda-stack', { // ๐Ÿ‘‡ pass the VPC from the other stack vpc: vpcStack.vpc, stackName: 'lambda-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });

In the code snippet we first instantiated the VPCStack and assigned the result to a variable.

We then instantiated our LambdaStack, passing in the VPC resource as a prop.

The code for this article is available on GitHub

Finally, let's add the code for the lambda function at src/my-lambda/index.js:

src/my-lambda/index.js
async function main(event) { console.log('VPC_ID ๐Ÿ‘‰', process.env.VPC_ID); return { body: JSON.stringify({message: `${process.env.VPC_ID} ๐ŸŽ‰`}), statusCode: 200, }; } module.exports = {main};

The function simply references and returns the id of the shared VPC.

The order of deployment matters, because our LambdaStack references the VPC resource from the VPCStack so it has to exist, before the LambdaStack is deployed.

Let's execute a deployment:

shell
npx cdk deploy

By looking at the Outputs section of our VPCStack, we can see that CDK has automatically created outputs for the components of the VPC, which will allow us to access it in our second stack:

vpc stack outputs

If we look at VPC section of the lambda function, we can see that it was provisioned in the shared VPC:

lambda uses shared vpc

Finally, if we execute the lambda function, via the management console, it returns the ID of the shared VPC:

lambda returns shared vpc id

Clean up #

We have to delete the lambda-stack first, because it references an output in the vpc-stack.

shell
npx cdk destroy lambda-stack npx cdk destroy vpc-stack

Further Reading #

Add me on LinkedIn

I'm a Web Developer with TypeScript, React.js, Node.js and AWS experience.

Let's connect on LinkedIn

Join my newsletter

I'll send you 1 email a week with links to all of the articles I've written that week

Buy Me A Coffee