Using nested CloudFormation templates to simplify stack management

One of my favorite CloudFormation features is nested stacks because it allows us to create template snippets and reference them from another template. This can greatly increase the readability of the CloudFormation templates, and increase the re-usability of the template.

The basic structure to nest a stack is pretty simplistic:

{
    "Type" : "AWS::CloudFormation::Stack",
    "Properties" : {
       "NotificationARNs" : \[ String, ... \],
       "Parameters" : { ... },
       "TemplateURL" : String,
       "TimeoutInMinutes" : String
    }
}

You declare a resource type of “stack”, with up to four parameters. The NotificationARNs parameter takes an array of SNS topics that should be alerted for the stack. The Parameters parameter takes in the parameters to pass to the nested stack. The TemplateURL parameter is the path to the nested json template, typically within S3. And finally the TimeoutInMinutes parameter specifies the maximum amount of time that the nested stack can take to be created.

So if we work from our cf-snippets-vpc.json template from my previous CloudFormation post, we could implement several VPCs at once using nested stacks. Example:

{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Description" : "Example that spawns multiple 1 subnet VPCs.",
    "Parameters" : {
        "CloudFormationPath" : {
            "Description" : "Path to the S3 template file.",
            "Type" : "String"
        }
    },
    "Conditions" : {},
    "Mappings" : {
        "VpcCidrMap" : {
            "vpc" : { "VpcTestA" : "10.0.0.0/23",    "VpcTestB" : "10.10.0.0/23" },
            "subnet" : { "VpcTestA" : "10.0.0.0/24",    "VpcTestB" : "10.10.0.0/24" }
        }
    },
    "Resources" : {
        "VpcTestA" : {
            "Type" : "AWS::CloudFormation::Stack",
            "Properties" : {
                "TemplateURL" : {"Fn::Join" : \["", \[{ "Ref" : "CloudFormationPath"}, "cf-snippets-vpc.json"\]\]},
                "Parameters" : {
                    "VPCName"           : "TestA",
                    "VPCCIDR"           : { "Fn::FindInMap" : \[ "CidrMap", "vpc", "VpcTestA"\] },
                    "PublicSubnet1AZ"   : { "Fn::Select" : \[ 0,{ "Fn::GetAZs" : { "Ref" : "AWS::Region" } }\]},
                    "PublicSubnet1CIDR" : { "Fn::FindInMap" : \[ "CidrMap", "subnet", "VpcTestA"\] }
                },
                "TimeoutInMinutes" : "60"
            }
        },
        "VpcTestB" : {
            "Type" : "AWS::CloudFormation::Stack",
            "Properties" : {
                "TemplateURL" : {"Fn::Join" : \["", \[{ "Ref" : "CloudFormationPath"}, "cf-snippets-vpc.json"\]\]},
                "Parameters" : {
                    "VPCName"           : "TestB",
                    "VPCCIDR"           : { "Fn::FindInMap" : \[ "CidrMap", "vpc", "VpcTestB"\] },
                    "PublicSubnet1AZ"   : { "Fn::Select" : \[ 0,{ "Fn::GetAZs" : { "Ref" : "AWS::Region" } }\]},
                    "PublicSubnet1CIDR" : { "Fn::FindInMap" : \[ "CidrMap", "subnet", "VpcTestB"\] }
                },
                "TimeoutInMinutes" : "60"
            }
        }

Official documentation on nested stacks is available on docs.aws.amazon.com.