This is the 2nd instalment in the series of “old dog learning new cloudformation tricks” ;-)

Problem

Story begins from a VPC template where I wanted to have an option to define secondary CIDR block so VPC could be expanded or reduced without re-creating the VPC itself. To keep things simple in this example I have only a VPC with single secondary CIDR block and one subnet. But because subnet may use addresses from the secondary CIDR block, I must use DependsOn for AWS::EC2::Subnet to declare explicit dependency to AWS::EC2::VPCCidrBlock ensuring the secondary CIDR block is attached to VPC before subnet is created.

This would be fine, if the secondary CIDR block would always be part of the stack, but the requirement was to be able to expand and shrink the VPC on demand, ie. AWS::EC2::VPCCidrBlock would have to be a conditional resource. In normal case I would use Fn::If to disable dependency when seconday CIDR block is not present.

  Subnet:
    Type: AWS::EC2::Subnet
    DependsOn: 
      Fn::If:
      - VpcCidrSecondaryExists
      - Ref: VPCSecondaryCIDR
      - Ref: AWS::NoValue

But this will fail template validation because DependsOn can not contain any functions :-(

Template format error: DependsOn must be a string or list of strings.

Solution

Solution is to create an intermediate resource where I can make conditional reference to AWS::EC2::VPCCidrBlock if it exists. In resource metadata it is perfectly fine to use Fn::If and reference to CIDR block only if it exists.

  VPCReady:
    Type: AWS::CloudFormation::WaitConditionHandle
    Metadata:
      SecondaryCIDRready: !If [ VpcCidrSecondaryExists, !Ref VPCSecondaryCIDR, "" ]

VPCReady is always created but it makes reference to conditional CIDR block only if it does exists in the stack. Now it is also safe to make subnet depend on VPCReady as it is not conditional resource. Problem (almost) solved!

It turns out that if I try to remove CIDR block and update the subnet using the block, update will fail to delete CIRD block as subnet deletion isn’t finished.

Fortunately Cloudformation will retry CIDR block delete and eventually succeed. If you don’t like red error messages, work-a-round is to make the update in 2 steps; first relocate subnet to free CIDR block and then remove CIDR block. Doing a single change at the time is a good practise anyways.

Resources