37.6 Nested Stacks and StackSets: Cross-Account and Cross-Region Deployments
Right, so you’ve mastered the single CloudFormation stack. You can build a VPC, an EC2 instance, and an RDS database all in one glorious, 500-line YAML file. It feels powerful, doesn’t it? Until you need to deploy the same darn thing to three different environments and two different regions. Suddenly, copying, pasting, and managing a dozen massive templates feels less like infrastructure as code and more like infrastructure as copy-paste nightmare.
This is where Nested Stacks and StackSets come in to save your sanity. They’re the tools that take you from a hobbyist building a single Lego model to an architect managing an entire Lego city.
The Humble Nested Stack: Breaking the Monolith
Think of a Nested Stack as CloudFormation’s version of a function or a module. Instead of one gigantic, unwieldy template, you break your infrastructure into logical, reusable components. The main, root stack doesn’t create resources directly. Instead, it contains AWS::CloudFormation::Stack resources that point to other templates. CloudFormation then goes and creates those as separate stacks, which are nested within the root.
Why bother? Reusability, isolation, and simplified management. You can create a template for a standard, compliant VPC and then reuse it across every single application stack you ever build. If you need to update that VPC, you change one file, not twenty. Also, if a deployment of a nested stack fails, it doesn’t necessarily blow up the entire root stack; they’re managed somewhat independently.
Here’s the root stack (main.yaml) that uses a nested stack for a network component:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MyNetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-bucket/network-template.yaml
Parameters:
VpcCidr: "10.0.0.0/16"
MyAppServer:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-12345678
InstanceType: t3.micro
# This is the magic: referencing an output from the nested stack
SubnetId: !GetAtt MyNetworkStack.Outputs.PublicSubnetId
And here’s the nested stack template (network-template.yaml) it calls:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
VpcCidr:
Type: String
Resources:
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: "10.0.1.0/24"
Outputs:
PublicSubnetId:
Value: !Ref PublicSubnet
Description: The ID of the public subnet
The Gotcha: Notice the TemplateURL. You can’t just use a local file path here. The template must be stored in a place CloudFormation can get to it at runtime, like an S3 bucket. This is the single biggest trip-up for beginners. I’ve lost hours of my life to forgetting to aws s3 cp my updated nested template before running the root stack update. CloudFormation will not, I repeat, will not, check for local changes. It uses the copy you previously uploaded to S3. It’s a design choice that is both infuriating and utterly predictable from a service that values immutability.
StackSets: Conquering Accounts and Regions
Now, let’s say you need that entire infrastructure—root stack and all its nested children—deployed across multiple AWS accounts or regions. Do you log in to each one and run aws cloudformation create-stack? Please don’t. That way lies madness and certain human error.
Enter StackSets. A StackSet is simply a CloudFormation resource that allows you to create, update, or delete stacks across multiple accounts and regions from a single operation. You define what you want (the template), where you want it (the accounts and regions), and how you want it deployed, and CloudFormation handles the rest.
Why it’s a game-changer: Consistency and governance. You can define a security baseline or a standard logging setup in one template and roll it out to every account in your Organization with a few commands. It’s the primary tool for central IT teams to enforce compliance at scale.
Creating a StackSet is a two-step process. First, you define the StackSet itself. Then, you create StackInstances—the actual stacks that will be deployed in each account-region pair.
Here’s how you create a StackSet using the AWS CLI. This deploys a simple S3 bucket to two regions in a single account (using --permission-model SELF_MANAGED). For multiple accounts, you’d use SERVICE_MANAGED permissions with AWS Organizations.
# Create the StackSet definition
aws cloudformation create-stack-set \
--stack-set-name MyApp-Standard-Buckets \
--template-body file://my-s3-bucket-template.yaml \
--permission-model SELF_MANAGED
# Now create the Stack Instances in specific regions
aws cloudformation create-stack-instances \
--stack-set-name MyApp-Standard-Buckets \
--accounts '["123456789012"]' \
--regions '["us-east-1","eu-west-1"]'
The Big, Honking Caveat: StackSets are powerful, but their error handling can be… philosophical. If a deployment to one account fails, the StackSet operation will often continue to other accounts and regions. This is good for overall progress but terrible if you need an all-or-nothing deployment. You must monitor the operation status and be prepared to handle partial failures. Always, always test your StackSet in a single non-prod account and region first. The console is your friend here for visualizing what succeeded and what failed.
Best Practices: Don’t Make My Mistakes
- Parameter Strategy: Use a consistent and rigorous parameter strategy for your nested stacks. The root stack should pass down everything the child needs. Consider using SSM Parameter Store for common values across all your stacks; it’s a cleaner solution than passing fifty parameters from the root.
- Output Everything: If you might need to reference a resource from a nested stack, add it to the
Outputssection. It’s far easier to add an output you don’t end up using than it is to update a nested stack later because you forgot one. - StackSets for Governance, Nested for Architecture: Use StackSets to deploy foundational, cross-account resources (like IAM roles, CloudTrail, Config rules). Use Nested Stacks to compose your actual application architecture (VPCs, ECS clusters, etc.) within an account.
- Assume Role is Your Friend: For cross-account StackSets, you will need to set up trust and execution roles. Read the docs on this twice. It’s a common point of failure, and the error messages aren’t always helpful. It’s the tax we pay for this power.
Mastering these two features is what separates someone who uses CloudFormation from someone who truly leverages it. It requires more upfront thought, but the payoff in maintainability and scale is absolutely worth it. Now go forth and stop copying and pasting YAML.