AWS Control Tower / Landing Zone
If your organization uses AWS Control Tower (a "landing zone") to manage accounts, you can deploy the Infracost integration once and have it automatically applied to every account in a target OU — including accounts created after you set this up. This uses the same cloudformation-aws-integration template as the CloudFormation guide, deployed as an AWS Organizations StackSet with auto-deployment enabled.
Not using Control Tower? See the CloudFormation or Terraform guides instead.
This integration requires access to your AWS organization's management account. Reach out to support@infracost.io before getting started if you have questions.
How it fits with Control Tower
Control Tower organizes accounts into OUs and governs them centrally, but it doesn't create the Infracost IAM role for you — that's what this guide sets up, using the same StackSet mechanism Control Tower itself relies on for guardrails.
- The management account (the landing zone's root/payer account) is deployed to once, directly — StackSets with service-managed permissions can't target it.
- Every account in your chosen OU (for example, the OU Control Tower vends new accounts into) gets the role via the StackSet.
- Auto-deployment means a brand-new account provisioned through Control Tower's Account Factory automatically picks up the role as soon as it lands in that OU — no manual step per account.
Prerequisites
- Access to the AWS console (or CLI) on your AWS organization's management account
- Control Tower already set up, with the OU(s) you want covered (for example
OU-Workloadsor aProduction/SandboxOU) - Permission to create IAM roles and policies, and to manage CloudFormation StackSets, in the management account
- Your Infracost External ID — in Infracost Cloud, go to Org Settings > General and copy the External ID. It is also shown on the AWS integration page.
Step 1: Deploy to the management account
StackSets with service-managed permissions can't target the management account, so deploy the template there directly, as a regular stack:
aws cloudformation deploy \
--template-file template.yaml \
--stack-name infracost-aws-integration \
--parameter-overrides \
InfracostExternalId=YOUR_EXTERNAL_ID \
IsManagementAccount=true \
--capabilities CAPABILITY_NAMED_IAM
Download template.yaml from the cloudformation-aws-integration repo first, or reference it directly from a URL you control.
Step 2: Enable trusted access for StackSets
One-time setup, run once from the management account:
aws organizations enable-aws-service-access \
--service-principal member.org.stacksets.cloudformation.amazonaws.com
aws cloudformation activate-organizations-access
Step 3: Create the StackSet with auto-deployment enabled
Enabled=true is what makes this a landing-zone setup rather than a one-off StackSet: it re-applies the stack to any account that later joins the target OU, and (optionally) removes it from accounts that leave.
aws cloudformation create-stack-set \
--stack-set-name infracost-aws-integration \
--template-body file://template.yaml \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false \
--capabilities CAPABILITY_NAMED_IAM \
--parameters ParameterKey=InfracostExternalId,ParameterValue=YOUR_EXTERNAL_ID
RetainStacksOnAccountRemoval=false deletes the Infracost role from an account when it's moved out of the target OU. Set it to true instead if you'd rather leave the role in place.
Step 4: Target your landing zone's OU
Point the StackSet at the OU that Control Tower's Account Factory vends new accounts into (or any other OU you want covered):
aws cloudformation create-stack-instances \
--stack-set-name infracost-aws-integration \
--deployment-targets OrganizationalUnitIds=YOUR_OU_ID \
--regions us-east-1
You can target multiple OUs by repeating this command, or by passing a comma-separated list to OrganizationalUnitIds.
Run this in us-east-1, even if you don't enable data exports — the template references a resource type (AWS::BCMDataExports::Export) that StackSets validates against the target region, and it's only registered in us-east-1.
From this point on, any account Control Tower provisions into that OU automatically gets the infracost-readonly role — nothing further to do per account.
Step 5: Add the integration in Infracost Cloud
- Get the management account's role ARN from its stack outputs:
aws cloudformation describe-stacks --stack-name infracost-aws-integration --query 'Stacks[0].Outputs' - In Infracost Cloud, go to Org Settings > Integrations > Add integrations, click Add integration for Amazon Web Services.
- Enter an Alias and the Role ARN from step 1.
- Click Test connection, then save.
Member accounts provisioned via the StackSet get the same role name (infracost-readonly) — Infracost discovers them once you've connected the management account, the same as with a manually-deployed org.
Step 6: Enable cost and usage data exports to Infracost
EnableDataExports is a management-account-only feature (it requires IsManagementAccount=true), and the StackSet in Step 3 only ever deploys to member accounts — never the management account. So enable it directly on the management account's standalone stack from Step 1, following Step 2 of the CloudFormation guide (prerequisites, parameters, and everything else are identical). Don't pass EnableDataExports to create-stack-set — the template rejects it unless IsManagementAccount=true, which would fail every member-account deployment in the StackSet.
Optional: anomaly detection, KMS
EnableAnomalyMonitors and KmsKeyArn are also management-account-only, for the same reason as above — configure them on the management account's standalone stack, not the StackSet. See Step 3 and the KMS section of the CloudFormation guide.
Upgrading
Update the StackSet's template, and the change rolls out to every account it manages, including ones added later:
aws cloudformation update-stack-set \
--stack-set-name infracost-aws-integration \
--template-body file://template.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--parameters ParameterKey=InfracostExternalId,ParameterValue=YOUR_EXTERNAL_ID
Also redeploy the management account's standalone stack (as in Step 1) since it's managed separately.
Removing
Remove stack instances from the target OU(s), then delete the StackSet, then the management account's standalone stack:
aws cloudformation delete-stack-instances \
--stack-set-name infracost-aws-integration \
--deployment-targets OrganizationalUnitIds=YOUR_OU_ID \
--regions us-east-1 \
--no-retain-stacks
aws cloudformation delete-stack-set --stack-set-name infracost-aws-integration
aws cloudformation delete-stack --stack-name infracost-aws-integration
Troubleshooting
See the CloudFormation guide's troubleshooting section — all the same failure modes apply here, since it's the same template.