The landing zone includes a generated GitHub Actions workflow that deploys the organization and landing-zone stacks to your management account on every push to main. 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-management.yml. It is generated by projen from .projenrc.ts, so edit .projenrc.ts to change it, not the workflow file directly.
The pipeline runs two deploy commands in sequence:
pnpm run management:deploy:organization: deploysOrganizationStack(Phase 1)pnpm run management:deploy:landingzone: deploysLandingZoneFoundationStackandLandingZoneAccountProvisioningStack(Phases 2 and 3)
Both commands run in the management GitHub environment. That environment name is significant: the GitHubActionsServiceRole trust policy is scoped to it, so workflows running outside the management environment cannot assume the role.
The GitHubActionsServiceRole
The landing zone foundation sets all of this up for you. The OIDC trust is created by GitHubActionsOidcConstruct inside OrganizationStack. On the first local deployment of the organization stack, it:
- Registers
token.actions.githubusercontent.comas an OIDC identity provider in your management account - Creates the
GitHubActionsServiceRoleIAM role withAdministratorAccessin your management account - Scopes the role's trust policy to your repository (resolved automatically from your git remote) and the
managementGitHub environment - Sets a
maxSessionDurationof 2 hours, so each pipeline run receives short-lived temporary credentials that expire automatically. Two hours is plenty to deploy a full landing zone change, and nothing long-lived is ever stored
This is a one-time setup. After the first pnpm run management:deploy:organization completes locally, the pipeline is authorized to run without any manual IAM configuration.
The net result: once you have run synth, the first organization deploy, and pnpm exec projen, you have a fully authenticated GitHub Actions pipeline that deploys every landing zone stack to your management account on each push to main, with no long-lived AWS keys anywhere and only temporary, time-boxed access.
The role ARN embedded in the workflow follows the pattern:
arn:aws:iam::<managementAccountId>:role/GitHubActionsServiceRole
This value is baked into the workflow by projen when you run pnpm exec projen. If your management 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.
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/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; each is trusted only for the management environment.
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 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 ID and region into the workflow andmanagement:*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
createCdkDeploymentWorkflowhelper insrc/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-management.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-management group. This means 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 a UPDATE_IN_PROGRESS state), so this is intentional.