AWS CDK Landing Zone

Install

Set up the AWS CDK Landing Zone from first clone to a fully deployed multi-account AWS environment.

Prerequisites

Before you start, make sure you have:

  • Node.js 24.18.0 or later: the project pins its Node version; check with node --version
  • pnpm: install via corepack enable (recommended) or brew install pnpm
  • AWS CDK CLI: npm install -g aws-cdk
  • projen: already included as a dev dependency, no separate install needed. projen is the project-generation tool that owns your configuration files: you edit .projenrc.ts and run pnpm exec projen to regenerate package.json, the management:* npm scripts, and the GitHub Actions workflow. Never hand-edit generated files; change .projenrc.ts instead. See the projen reference for how it works
  • An AWS management account: the root account of your AWS Organization. If you don't have an organization yet, the landing zone creates one for you in Phase 1
  • GitHub repository: the starter expects a GitHub remote; the OIDC trust policy is scoped to your repository

Step 1: Create your repository from the template

Click Use this template on the cdk-landing-zone-starter GitHub repository to create your own private copy, then clone it:

git clone git@github.com:<your-org>/<your-repo>.git
cd <your-repo>

Step 2: Get your management account whitelisted

Share your management account ID with Towards The Cloud. We whitelist it on the private CodeArtifact registry that hosts @towardsthecloud/cdk-landing-zone-constructs and @towardsthecloud/cdk-landing-zone-foundation. Until your account is whitelisted, pnpm install cannot resolve these packages.

Step 3: Install dependencies

Assume a role or configure credentials in your whitelisted management account, then run:

pnpm run setup

This logs in to CodeArtifact and runs pnpm install --frozen-lockfile in one step. The login script (scripts/codeartifact-login.sh) fetches an auth token and writes it as a registry-scoped _authToken in your user-level ~/.npmrc. It does not change your default npm registry. Tokens are valid until your AWS session expires. If pnpm install returns a 401, re-assume your role and run pnpm run setup again.

Step 4: Configure landing zone settings

Open src/config/landing-zone-settings.ts and replace every placeholder value:

export const landingZoneSettings: LandingZoneSettings = {
  organizationName: 'your-org', // short slug, lowercase and dashes
  mailDomain: 'your-org.com', // domain for generated account email addresses
  managementAccountId: '123456789012', // 12-digit management account ID
  primaryRegion: 'eu-west-1', // main deployment region
  secondaryRegions: [], // additional regions for multi-region StackSets
};

See Landing Zone Settings for the full field reference.

Optional settings

Only add these fields when you explicitly need the extra behavior:

export const landingZoneSettings: LandingZoneSettings = {
  // ...required settings above
  externalAdmins: [
    { accountId: '111122223333', managedPolicyName: 'ReadOnlyAccess' },
  ], // grants third-party access through the optional ExternalAccessStackSet
  organizationAccountLimit: 120, // requests an AWS Organizations account quota increase
};

Use externalAdmins when a trusted third-party account needs cross-account access. Use organizationAccountLimit only when your planned account count exceeds the current AWS Organizations quota.

Step 5: Configure your organization structure

Open src/config/organization-structure.ts and replace the example Workload Alpha/Workload Beta accounts with your own OUs and accounts. Every account needs a unique, valid email address.

See Organization Structure for the full field reference and constraints.

Step 6: Configure alternate contacts

Open src/config/alternate-contacts.ts and set the real security, billing, and operations contacts for your organization. These are applied to every account.

See Alternate Contacts for the field reference.

Step 7: Regenerate project files

Run projen to embed your management account ID and primary region into the generated npm scripts and GitHub Actions workflow:

pnpm exec projen

Re-run this command whenever you change landing-zone-settings.ts.

Step 8: Bootstrap the CDK toolkit

cdk bootstrap aws://123456789012/eu-west-1

Replace the account ID and region with your management account values.

Step 9: First deployment (two phases)

The initial rollout is intentionally split. The organization must exist before the landing zone StackSets can target its accounts.

Phase 1: Deploy the organization stack

Run this locally:

pnpm run management:deploy:organization

This creates your AWS Organization, OUs, accounts, SCPs, and SSM parameters. It also creates the GitHub Actions OIDC provider and GitHubActionsServiceRole in your management account, scoped to your repository, so the CI/CD pipeline is authorized to deploy after this step without any further IAM setup.

Synthesize after Phase 1

After the organization stack deploys, run synth to populate cdk.context.json with the SSM-published OU and account IDs:

pnpm run management:synth

The landing-zone StackSets use these cached IDs to target the right accounts. Make sure cdk.context.json is populated (it will contain /organization/... entries) before proceeding.

Phase 2: Deploy the landing zone stacks

Pick whichever fits your workflow:

Push to main and let GitHub Actions deploy:

git add cdk.context.json
git commit -m "chore: add cdk context after org deploy"
git push

Or deploy locally:

pnpm run management:deploy:landingzone

Or deploy everything in one command (what the pipeline runs on every push):

pnpm run management:deploy

Ongoing deployments

After the initial rollout, every push to main triggers the GitHub Actions pipeline, which runs pnpm run management:deploy. You can also deploy locally with the same command at any time.

To update the landing zone packages, see Updating Versions.