Skip to main content

CDK Cross-Account Resource Example

A practical example demonstrating how to manage AWS resources across multiple accounts using CDK and orbits. This project showcases an hello-world example : it deploys an AWS Systems Manager parameter in Account A and read it from a Lambda function in Account B.

Problem statement

Using AWS CDK and CloudFormation, consuming cross-account resources is difficult because stacks cannot directly reference resources from other AWS accounts. The core issue is that CloudFormation stacks cannot directly reference resources from other AWS accounts, requiring manual coordination and hardcoded values Common problematic scenarios include:

  • Accessing Docker images built in account A from account B
  • Using secrets from account A in account B applications
  • Establishing VPC peering between accounts
  • Granting cross-account S3 bucket access
  • Sharing Lambda layers across accounts
  • Writing values into the DNS zone of account A from account B

This limitation is shown in this example:

const app = new cdk.App()

const paramA = new ParamStack(app, 'stack-A', {
...,
env: {
account: "account-A"
}
})

const lambdaB = new LambdaStack(app, 'stack-A', {
...,
parameterArn : paramA.parameter.arn, // ❌ you can not reference a resource from a stack from another account
env: {
account: "account-B"
}
})

With orbits, cross-account resource sharing works seamlessly:

const paramOutput = await this.do("updateParam", new ParamResource());

await this.do("updateLambda", new LambdaResource().setArgument({
stackProps : {
parameterArn: paramOutput.parameterArn,// ✅ you can reference any stack
env: {
account : this.argument.accountA.id
}
}
}))

Architecture Overview

Prerequisites

Clone this repository

cd samples/cross-account-aws-cdk
  • Install node.js dependencies : npm i

Setup AWS environment

You'll need access to two AWS accounts with the following permissions:

Account A: CloudFormation deployment rights Account B: CloudFormation deployment rights

Configure environment values

  • Copy the environment template: bash cp .base.env .env
  • Edit .env file with your account details.

Deployment

  • Load environment variables: bash export $(cat .env | xargs)

  • Define your mongo_url : bash export ORBITS_DB__MONGO__URL=your-mongo-url

  • Deploy Cross-Account Infrastructure bash npx tsx src/orbits/orbi.ts This command will:

  • Deploy the SSM parameter in Account A

  • Create the Lambda function in Account B with appropriate cross-account permissions

  • Set up the necessary IAM roles and policies for cross-account access

Verify the result of Lambda Function

  • Navigate to the AWS Console for Account B

  • Go to Lambda service

  • Find the deployed function (typically named with a stack prefix)

  • Click Test to create a test event

  • Execute the test

  • Expected Output The Lambda function should successfully retrieve the parameter from Account A and should display the value of parameter A in its logs. typescript console.log('Param:', param.Parameter.Value); The default value of parameter is "hello-world".

Cleanup

To remove all deployed resources from both accounts:

export HELLO_COMMAND=uninstall
npx tsx src/orbits/orbi.ts

⚠️ Warning: This will permanently delete all resources created by this example. Make sure you want to remove everything before running this command.

Project Structure

├── src/
│ ├── orbits/
│ │ └── orbi.ts # Main orchestration script
│ │ ├── lambda-resource.ts # lambda resource definition
│ │ ├── param-resource.ts # Param resource definition
│ │ ├── hello-resource.ts # Hello resource definition : the resource that make the junction between param and lambda

│ ├── cdk/ # CDK stack definitions
│ │ ├── lambda.ts # lambda CDK stack
│ │ ├── param.ts # Param CDK stack
├── .base.env # Environment template
├── .env # Your environment variables (git-ignored)
├── package.json
└── README.md

Step-by-step explanation

For a detailed walkthrough of the different files and how they work together, check out this blog post.

Security Considerations

The cross-account access follows the principle of least privilege Parameters are accessed using IAM roles, not hardcoded credentials CloudFormation stacks can be easily audited for security compliance