The landing zone rolls out its account baseline through CloudFormation StackSets. Which StackSets deploy, and to which accounts, OUs, and regions, is controlled by createStackSet calls in two files under src/stacks/. The StackSet implementations themselves live in src/stacksets/ and are separate from the targeting logic.
For a full inventory of what each StackSet deploys, see the StackSets reference.
The two stack files that control deployment
| File | Governs |
|---|---|
src/stacks/landing-zone-foundation-stack.ts | LogArchiveStackSet, CentralAlertsStackSet, ProvisionManagementStackSet |
src/stacks/landing-zone-account-provisioning-stack.ts | AccountSecurityStackSet, OrganizationSecurityStackSet, CostControlStackSet, CdkBootstrapStackSet, ServiceQuotasStackSet, SecurityHubV2StackSet |
Both files belong to the landing-zone phase and deploy from the landing zone account. Do not edit the StackSet implementation files in src/stacksets/ to change targeting. Only edit the target and regions arguments in the stack files above.
Changing security services and quotas
Configure CSPM, GuardDuty, Inspector, and Macie in security-services.ts. Set a service’s enabled option to false to disable that capability while keeping SecurityHubV2StackSet deployed. Its unified Security Hub V2 hub remains enabled. Removing the entire StackSet is a separate operation with different retention behavior.
Configure workload quota increase requests in service-quotas.ts. Keep an entry’s key when changing its requested value. Removing an entry does not lower a quota already granted.
Disabling a StackSet
To disable a StackSet, comment out or remove its createStackSet block from the relevant stack file and redeploy. CloudFormation removes the StackSet and its stack instances; resources with retention policies can remain. Review the resource retention behavior before deploying the removal.
// Disable CostControlStackSet by commenting out the block:
// landingZone.createStackSet(this, {
// name: 'CostControlStackSet',
// description: 'Set up cost control measures for organization accounts',
// stackSetStack: new CostControlStackSetStack(this, 'CostControlStackSetStack', {
// securityAccountEmail,
// }),
// target: StackSetTarget.fromOrganizationalUnits({
// regions: [this.region],
// organizationalUnits: [orgVars.RootOUId],
// }),
// });
To re-enable it, uncomment the block and redeploy.
Dependencies to respect:
- Keep
LogArchiveStackSetandCentralAlertsStackSetenabled whileProvisionManagementStackSetuses them. OrganizationSecurityStackSetconsumes the log archive bucket thatLogArchiveStackSetcreates and the notifications topic thatCentralAlertsStackSetcreates, plus the CloudTrail, IAM, and IAM Access Analyzer delegated-admin registrations owned by the organization phase. KeepLogArchiveStackSetandCentralAlertsStackSetenabled wheneverOrganizationSecurityStackSetis.SecurityHubV2StackSetrequires the security-service delegated administrators configured in the organization phase. Keep the corresponding entries in delegated-admins.ts while those services are enabled. New workload accounts do not need published IDs for security-service enrollment.AccountSecurityStackSetcovers member accounts through a service-managed StackSet, while the management account receives the same hardening from theSecureDefaultsConstructinsideProvisionManagementStackSet. Disabling one without the other leaves a gap in coverage.
Changing OU and account targets
Each createStackSet call takes a target that controls where the StackSet deploys. The OU and account IDs come from orgVars, which resolves them cross-account from the LandingZoneOrganizationStack CloudFormation outputs. OU IDs are always available; an account ID is only available as orgVars.<Key>Id when that account sets publishAccountIdOutput: true in organization-structure.ts. Two targeting patterns are available:
Target whole OUs or the root (service-managed):
target: StackSetTarget.fromOrganizationalUnits({
regions: [this.region],
organizationalUnits: [orgVars.RootOUId],
}),
New accounts that join the targeted OU automatically receive the StackSet instance; accounts that leave have it removed. Swap orgVars.RootOUId for any OU ID from your organization structure, for example [orgVars.DevelopmentOUId, orgVars.ProductionOUId] to limit a StackSet to workload accounts only.
Target explicit accounts (self-managed):
target: StackSetTarget.fromAccounts({
regions: [this.region, ...secondaryRegions],
accounts: [orgVars.SecurityAccountId],
}),
Use fromAccounts to deploy to specific accounts by ID. It makes the StackSet self-managed: cdk-stacksets selects this model automatically for direct account targets, because a target list without organization root or OU IDs cannot use the service-managed model. The built-in LogArchiveStackSet, CentralAlertsStackSet, ProvisionManagementStackSet, OrganizationSecurityStackSet, and SecurityHubV2StackSet all target a single account this way.
Any account ID you pass here must be resolvable: the management account comes from settings.managementAccountId, while a landing-zone account ID like orgVars.SecurityAccountId is only available when that account sets publishAccountIdOutput: true in organization-structure.ts. This is the main reason the log archive and security accounts opt into their ID outputs.
Self-managed StackSets are also the only model that can reach the management account (service-managed StackSets cannot), and they need the StackSet IAM roles that LandingZoneFoundationConstruct creates in the foundation stack.
Changing regions
The regions array on each target controls which regions receive a StackSet instance. Most StackSets deploy only to the primary region ([this.region]). Region-sensitive StackSets (secure defaults and central alerts) also cover secondaryRegions from your settings.
To add a region to a specific StackSet:
target: StackSetTarget.fromOrganizationalUnits({
regions: [this.region, ...secondaryRegions, 'ap-southeast-1'],
organizationalUnits: [orgVars.RootOUId],
}),
Adding a region that isn't in landing-zone-settings.ts's secondaryRegions is valid, but the region guardrail SCP may block API calls in that region unless you also add it to secondaryRegions. See Landing Zone Settings for how regions are configured.
Deployment rollout behavior
Each createStackSet call accepts an optional deploymentOptions (StackSetDeploymentOptions), which controls how CloudFormation rolls the StackSet out across its target accounts: concurrency (maxConcurrentAccounts or maxConcurrentAccountsPercentage) and failure tolerance (failureToleranceAccounts or failureToleranceAccountsPercentage). Set at most one count-or-percentage variant per option.
Left unset, a StackSet deploys to every target account at once and stops the whole operation if a single account's deployment fails. AccountSecurityStackSet, CostControlStackSet, CdkBootstrapStackSet, and ServiceQuotasStackSet instead pass a shared fastRolloutDeploymentOptions constant (maxConcurrentAccountsPercentage: 100, failureToleranceAccountsPercentage: 99), so a failure in one account does not stop the rollout to the rest of the organization. Pass your own deploymentOptions to any createStackSet call to change this per StackSet.
Preview and deploy
These StackSets belong to the landing-zone phase, so preview and deploy them from the landing zone account. Preview the diff first:
pnpm run landingzone:diff:all
Then deploy:
pnpm run landingzone:deploy:all
CloudFormation handles adding and removing StackSet instances as the target changes. Removing an OU from a target removes stack instances from all accounts currently in that OU; adding one deploys instances to all accounts already there.