Introducing CloudFormation Conditionals

Back in November 2013 Amazon added a much requested feature to CloudFormation, the ability to conditionally include resources or their properties in to a stack. As an example I’m currently using this as a small cost saving measure to ensure only my production RDS instances have PIOPs applied to them while being able to build each environment from a single template.

CloudFormation Conditionals live in their own section of a CloudFormation template. In the example below we show two ways of setting values for use in a condition. A simple string comparison and a longer, composite comparison that includes an or. Each of these are based on a provided parameter.

{
  "AWSTemplateFormatVersion": "2010-09-09",

  "Parameters" : {
    "DeploymentEnvironment" : {
      "Default": "dev",
      "Description" : "The environment this stack is being deployed to.",
      "Type" : "String",
      "AllowedValues" : [ "dev", "stage", "prod" ],
      "ConstraintDescription" : "Must be one of the following environments - dev | stage | prod"
    }
  },

  "Conditions": {
    "InProd": { "Fn::Equals" : [ { "Ref" : "DeploymentEnvironment" }, "prod" ] },

    "NotInProd": {
      "Fn::Or" : [
        { "Fn::Equals" : [ { "Ref" : "DeploymentEnvironment"}, "stage" ] },
        { "Fn::Equals" : [ { "Ref" : "DeploymentEnvironment"}, "dev" ] }
      ]
    }
  }
}

Our first example is the conditional inclusion of an entire resource -

  "Resources" : {

    "WebappSG": {
      "Type": "AWS::EC2::SecurityGroup",
      "Condition" : "NotInProd",
      "Properties": {
        "GroupDescription": "Location webapp servers",
        "SecurityGroupIngress": [ {
          ... snip ...
        } ]
      }
    }
  }

The key part of this snippet is the ‘Condition’ line. If the value on the right hand evaluates to true the resource is created when the template runs. If the condition is false the entire resource is skipped. As a second example we’ll show how to conditionally include a single property value. In this case the ‘Iops’ property of a AWS::RDS::DBInstance resource.

  "Resources" : {

    "MySQL" : { 
      "Type" : "AWS::RDS::DBInstance",
      "DeletionPolicy" : "Snapshot",
      "Properties" : { 
        "DBName"               : "testy",
        "AllocatedStorage"     : "5",
        "DBInstanceClass"      : "db.m2.4xlarge",
        "MasterUsername"       : "testy",
        "MasterUserPassword"   : "testy",
        "DBSecurityGroups"     : [ "rds" ],
        "Engine"               : "MySQL",
        "EngineVersion"        : "5.6",
        "MultiAZ"              : "true",
        "Iops" : {
          "Fn::If" : [ "InProd",
            "1000",
            { "Ref" : "AWS::NoValue" }
          ]
        }
      }
    }
  }

If InProd is true the Iops property is included and set to 1000. If the value of InProd is false then the special value of ‘AWS::NoValue’ is returned. This causes the property itself to be completely excluded.

CloudFormation Conditions are quite a new feature, and I was a little late in discovering it, so we’ve only just started to use them in our templates. They are however worth learning about as they provide a flexible new way to structure your templates.