The landing zone includes a generated GitHub Actions workflow that deploys both phases on every push to main: the organization phase to your management account, then the landing-zone phase to your landing zone account. It authenticates through GitHub's OIDC provider, so no long-lived AWS credentials are stored in GitHub Secrets.
How the pipeline works
The workflow file lives at .github/workflows/cdk-deploy-landing-zone.yml. It is generated by projen from .projenrc.ts, so edit .projenrc.ts to change it, not the workflow file directly.
The pipeline runs the two phases against two different accounts in one run:
- It assumes
GitHubActionsServiceRolein your management account and runspnpm run organization:deploy, which deploysLandingZoneOrganizationStack. - It re-configures credentials to assume
GitHubActionsServiceRolein your landing zone account and runspnpm run landingzone:deploy:all, which deploysLandingZoneFoundationStackandLandingZoneAccountProvisioningStack.
Both roles are named GitHubActionsServiceRole, one per account, and both trust only your repository. Dependencies are installed once with pnpm run setup before the organization phase and reused for the landing-zone phase.
The GitHubActionsServiceRole
The landing zone sets this up for you. The management-account role is created by GitHubActionsOidcConstruct inside LandingZoneOrganizationStack; the matching landing-zone-account role is bootstrapped by the same organization phase when it prepares the landing zone account. On the first local deployment of the organization stack, it:
- Registers
token.actions.githubusercontent.comas an OIDC identity provider in each account - Creates a
GitHubActionsServiceRolewithAdministratorAccessin the management account and a deploy role in the landing zone account - Scopes each role's trust policy to your repository, resolved automatically from your git remote
- Sets a short
maxSessionDurationso each pipeline run receives temporary credentials that expire automatically, with nothing long-lived stored anywhere
This is a one-time setup. After the first pnpm run organization:deploy completes locally and you have set landingZoneAccountId and re-run projen, the pipeline is authorized to run both phases without any manual IAM configuration.
The role ARNs embedded in the workflow follow the pattern:
arn:aws:iam::<managementAccountId>:role/GitHubActionsServiceRole
arn:aws:iam::<landingZoneAccountId>:role/GitHubActionsServiceRole
These values are baked into the workflow by projen when you run pnpm exec projen. If either account ID changes, re-run projen and the workflow updates automatically.
CodeArtifact access
The workflow runs pnpm run setup before deploying. This script authenticates to the private CodeArtifact registry that hosts @towardsthecloud/cdk-landing-zone-constructs and @towardsthecloud/cdk-landing-zone-foundation, then runs pnpm install --frozen-lockfile. The authentication works because:
- The workflow assumes
GitHubActionsServiceRolein your management account via OIDC - Towards the Cloud whitelists your management account on the CodeArtifact repository during initial setup
- The whitelisted account can fetch an auth token from CodeArtifact without further configuration
No separate secret is needed for package installation. The installed node_modules carry over to the landing-zone phase, so setup runs once.
Trusting additional repositories
By default, only the repository resolved from your git remote can assume GitHubActionsServiceRole. If you need a second repository (for example, a separate infrastructure repo) to deploy the landing zone, add it to GitHubActionsOidcConstruct in src/stacks/landing-zone-organization-stack.ts via the additionalRepositories prop. This requires editing the construct instantiation, which lives in a file you own. The additionalRepositories prop accepts bare repository names under the same GitHub owner.
Regenerating the workflow with projen
The workflow file is managed by projen. Editing it directly works but those changes are overwritten the next time someone runs pnpm exec projen. Instead, make changes through .projenrc.ts:
- To change the management or landing zone account ID or primary region: update
landing-zone-settings.tsand then runpnpm exec projen. Projen reads the settings at synthesis time and embeds the updated account IDs and region into the workflow and theorganization:*andlandingzone:*npm tasks. - To change the Node.js version: update the
nodeVersionconstant in.projenrc.tsand runpnpm exec projen. Both thesetup-nodestep and the.nvmrcfile update together. - To add a workflow step: extend the CDK deployment workflow helper in
src/bin/cicd-helper.tsor add a projen workflow step in.projenrc.ts.
After any .projenrc.ts change, commit both the updated .projenrc.ts and the regenerated .github/workflows/cdk-deploy-landing-zone.yml.
Manual dispatch
The workflow supports workflow_dispatch, so you can trigger a deploy from the GitHub Actions UI without pushing a commit. This is useful for forcing a re-deploy after a settings change that doesn't touch any tracked file, or for recovering from a partially failed pipeline run.
Concurrency
The workflow sets concurrency.cancel-in-progress: false for the cdk-deploy-landing-zone group. A second push while a deploy is in progress queues rather than cancels the running deploy. CDK deployments are not safe to cancel mid-run (CloudFormation can be left in an UPDATE_IN_PROGRESS state), so this is intentional.