Home / AWS

AWSHow-toAdvanced

CloudFormation StackSets across an AWS Organization: service-managed deployment, auto-deploy and safe rollouts

Deploy baseline resources (roles, Config rules, alarms, logging) to every account and region with service-managed StackSets, roll out with concurrency and failure tolerance, handle drift and failed instances, and avoid the classic StackSet traps.

Deepak Bhardwaj4 min read

Applies toAWS CloudFormation StackSets (service-managed permissions with AWS Organizations, self-managed permissions), AWS CLI v2

StackSets deploy one CloudFormation template to many accounts and regions. With service-managed permissions they integrate with AWS Organizations: new accounts in an OU get the stack automatically. That makes them ideal for account baselines, and dangerous if a bad change rolls to 300 accounts at once.

Permission models

Service-managed Self-managed
Who creates execution roles CloudFormation, through Organizations You, in every target account
Targets OUs (and accounts within them) Account IDs
Auto-deploy to new accounts Yes No
Use when Org-wide baselines Targets outside the org, or specific trust needs

Enable trusted access once from the management account, and register a delegated administrator so day-to-day work happens outside the management account:

aws cloudformation activate-organizations-access
aws organizations register-delegated-administrator --account-id 444444444444 --service-principal member.org.stacksets.cloudformation.amazonaws.com

From the delegated admin account, pass --call-as DELEGATED_ADMIN on StackSet commands.

Create a StackSet

aws cloudformation create-stack-set --stack-set-name baseline-security \
  --template-body file://baseline-security.yaml \
  --permission-model SERVICE_MANAGED \
  --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false \
  --capabilities CAPABILITY_NAMED_IAM \
  --managed-execution Active=true \
  --call-as DELEGATED_ADMIN

--managed-execution Active=true lets CloudFormation run non-conflicting operations concurrently instead of queuing them.

Deploy with guardrails

aws cloudformation create-stack-instances --stack-set-name baseline-security \
  --deployment-targets OrganizationalUnitIds=ou-abcd-sandbox \
  --regions eu-west-1 eu-central-1 \
  --operation-preferences RegionConcurrencyType=SEQUENTIAL,MaxConcurrentPercentage=10,FailureTolerancePercentage=0 \
  --call-as DELEGATED_ADMIN
Preference Meaning Safe default
MaxConcurrentCount/Percentage Accounts per region at the same time 10%
FailureToleranceCount/Percentage Failures allowed per region before the operation stops 0 for risky changes
RegionConcurrencyType Regions one after another or in parallel SEQUENTIAL
RegionOrder Which region goes first Least critical first

Roll out by ring: sandbox OU, then non-prod OU, then prod OU, as separate operations you check between.

Updates and overrides

aws cloudformation update-stack-set --stack-set-name baseline-security \
  --template-body file://baseline-security.yaml --capabilities CAPABILITY_NAMED_IAM \
  --deployment-targets OrganizationalUnitIds=ou-abcd-nonprod --regions eu-west-1 \
  --operation-preferences MaxConcurrentPercentage=20,FailureTolerancePercentage=0 \
  --call-as DELEGATED_ADMIN

Per-account or per-OU parameter values:

aws cloudformation update-stack-instances --stack-set-name baseline-security \
  --deployment-targets OrganizationalUnitIds=ou-abcd-prod --regions eu-west-1 \
  --parameter-overrides ParameterKey=AlarmEmail,ParameterValue=prod-oncall@example.com \
  --call-as DELEGATED_ADMIN

Warning

An update that omits --deployment-targets and --regions applies to every instance. For a big StackSet that is your whole estate in one operation.

When instances fail

aws cloudformation list-stack-set-operations --stack-set-name baseline-security --call-as DELEGATED_ADMIN --max-results 5
aws cloudformation list-stack-set-operation-results --stack-set-name baseline-security \
  --operation-id <op-id> --call-as DELEGATED_ADMIN \
  --query "Summaries[?Status=='FAILED'].[Account,Region,StatusReason]" --output table
aws cloudformation list-stack-instances --stack-set-name baseline-security --call-as DELEGATED_ADMIN \
  --filters Name=DETAILED_STATUS,Values=FAILED --output table
Status reason Cause Fix
ResourceLogicalId: Already exists Named resource (IAM role, bucket) already in the account Import it, rename, or delete the stray one
Account ... should have 'AWSCloudFormationStackSetExecutionRole' Self-managed model without execution role Deploy the role
Region disabled / not opted in Target region not enabled in that account Enable region or remove it from targets
INOPERABLE instance Stack deleted outside StackSets, or account left org delete-stack-instances --retain-stacks, then recreate
SCP denies an action Guardrail blocks the template Exclude the StackSet execution role in the SCP or change the template

Drift

aws cloudformation detect-stack-set-drift --stack-set-name baseline-security --call-as DELEGATED_ADMIN
aws cloudformation describe-stack-set --stack-set-name baseline-security --call-as DELEGATED_ADMIN \
  --query "StackSet.StackSetDriftDetectionDetails"

Fix drift by redeploying the instance, not by editing in the console.

Prevent it next time

  • Keep StackSet templates in Git; changes go through a pipeline that deploys to the sandbox OU first.
  • Zero failure tolerance and small concurrency for anything touching IAM or networking.
  • Avoid hard-coded resource names in baseline templates; let CloudFormation generate them or include the account ID.
  • Delegated admin for StackSets, so the management account is barely used.