Skip to main content

nested cloudformation stack

create sub stack vpc.yml

$ cat vpc.yml 
AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  CidrBlock:
    Type: String
    Default: "10.0.0.0/16"
  NameTag :
    Type: String
    Default: "nested stack"

Resources:
  VPC:

    Properties:
      CidrBlock: !Ref CidrBlock
      Tags:
      - Key: Name
        Value: !Ref NameTag

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: !Ref NameTag

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: 
        Ref: VPC
      InternetGatewayId:
        Ref: InternetGateway

Outputs:
  VpcId: 
    Value: !Ref VPC
  IgwId:
    Value: !Ref InternetGateway
aws cloudformation validate-template --template-body file://vpc.yml

create another sub stack subnet.yml

$ cat subnet.yml                                                                                                                                                [5/1860]
AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  NameTag:
    Type: String
    Default: "subnetnesting"
  VPC:
    Type: AWS::EC2::VPC::Id
  CidrBlock1:
    Type: String
    Default: "10.0.0.0/24"
  CidrBlock2:
    Type: String
    Default: "10.0.1.0/24"

Resources:
  Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref CidrBlock1
      AvailabilityZone:
         Fn::Select:
         - '0'
         - Fn::GetAZs:
             Ref: AWS::Region

  Subnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref CidrBlock2
      AvailabilityZone:
         Fn::Select:
         - '1'
         - Fn::GetAZs:
             Ref: AWS::Region

Outputs:
  SubnetId1:
    Value: !Ref Subnet1
  SubnetAz1:
    Value: !GetAtt Subnet1.AvailabilityZone
  SubnetId2:
    Value: !Ref Subnet2
  SubnetAz2:
    Value: !GetAtt Subnet2.AvailabilityZone
aws cloudformation validate-template --template-body file://subnet.yml

create parent stack parent.yml

$ cat parent.yml 
AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  NameTag:
    Default: nested stack test
    Type: String
  CidrBlock:
    Default: 10.1.0.0/16
    Type: String
  CidrBlock1:
    Default: 10.1.0.0/24
    Type: String
  CidrBlock2:
    Default: 10.1.1.0/24
    Type: String

Resources:
  VPC:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: vpc.yml
      Parameters:
        NameTag : !Ref NameTag
        CidrBlock: !Ref CidrBlock

  SUBNET:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: subnet.yml
      Parameters:
        NameTag : !Ref NameTag
        VPC: !GetAtt VPC.Outputs.VpcId
        CidrBlock1: !Ref CidrBlock1
        CidrBlock2: !Ref CidrBlock2

Outputs:
  VpcId:
    Value: !GetAtt VPC.Outputs.VpcId
  SubnetId1:
    Value: !GetAtt SUBNET.Outputs.SubnetId1
  SubnetId2:
    Value: !GetAtt SUBNET.Outputs.SubnetId2
aws cloudformation validate-template --template-body file://parent.yml

create or update stack

aws cloudformation package --template-file parent.yml --s3-bucket your-s3bucket-name --output-template-file parent_packaged.yml
aws cloudformation deploy --template-file parent_packaged.yml --stack-name nestedstack --tags Name=testnestedstack

confirm

$ aws cloudformation describe-stacks --query 'Stacks[?Tags[?Key == `Name` && Value == `testnestedstack`]]' | less

$ aws cloudformation describe-stacks --query 'Stacks[?Tags[?Key == `Name` && Value == `testnestedstack`]].StackName' | jq -r .[] | while read stackname; do
> aws cloudformation describe-stack-events --stack-name ${stackname}
> done | less

    $ aws cloudformation describe-stacks --query 'Stacks[?Tags[?Key == `Name` && Value == `testnestedstack`]].StackName' | jq -r .[] | while read stackname; do
> aws cloudformation describe-stack-resources --stack-name ${stackname}
> done | less

delete stack

aws cloudformation delete-stack --stack-name nestedstack