AWS: CloudFormation  - using Conditions, Fn::Equals, and Fn::If -  an example
Tags: aws, automation, tutorial
Published: 2020-05-18 03:30:59

---
title: AWS: CloudFormation  - using Conditions, Fn::Equals, and Fn::If -  an example
published: true
date: 2020-05-17 01:59:35 UTC
tags: aws,automation,tutorial
canonical_url: https://rtfm.co.ua/en/aws-cloudformation-using-conditions-fnequals-and-fnif-an-example/
---

### AWS: CloudFormation — using Conditions, Fn::Equals, and Fn::If — an example

![](https://cdn-images-1.medium.com/max/130/0*AFhpnxWpmaV5i3Sz.png)

I have a CloudFormation stack with [VPC Peerings](https://rtfm.co.ua/aws-nastrojka-vpc-peering/), in that case, it’s a peering between VPC of a new Elastic Kubernetes Service cluster and VPC of the Prometheus monitoring stack.

The EKS cluster’s stack and its whole automation creation were described in the [AWS Elastic Kubernetes Service: a cluster creation automation, part 1 — CloudFormation](https://rtfm.co.ua/en/aws-elastic-kubernetes-service-a-cluster-creation-automation-part-1-cloudformation/) and [AWS Elastic Kubernetes Service: a cluster creation automation, part 2 — Ansible, eksctl](https://rtfm.co.ua/en/aws-elastic-kubernetes-service-a-cluster-creation-automation-part-2-ansible-eksctl/) posts.

**The task** : add an ability to chose if CloudFormation have to create the peering mentioned above — or skip this step.

**The solution** : use the [AWS CloudFormation Conditions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html): will add a new parameter VPCPeeringCreate which will accept a _true_ value _false_ from a Jenkins job and then depending on this value CloudFormation will decide if need to create such a peering and related resources - the peering itself and two Routes.

The task is becoming a bit more complicated due to the fact, that I have Nested Stacks used there and resources are created by different stacks, so to create a peering it uses:

- root-stack:
- will create a Region and AvalabilityZones-located stacks
- in the Region-stack:
- will create AWS::EC2::VPCPeeringConnection
- will update a RouteTable of the remote Monitoring stack with Prometheus — will create a new AWS::EC2::Route (a route from the Monitoring VPC into the EKS stack's VPC)
- in itsOutputs will return a _MonitoringProdVPCPeeringConnectionID_
- AvalabilityZones-located stack:
- will grab the _MonitoringProdVPCPeeringConnectionID_
- will create an AWS::EC2::Route (a route from the EKS cluster's VPC private subnets to the Monitoring stack VPC)

So, let’s add them one-by-one to see how this is working.

#### Root stack

In the Parameters of the Root stack add a new parameter called _VPCPeeringCreate_, which can accept _true_ or _false_:

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "AWS CloudFormation stack for Kubernetes cluster",

  "Parameters": {

...

    "VPCPeeringCreate": {
      "Description": "Create or not VPC peering connections",
      "Type": "String",
      "Default": true,
      "AllowedValues": [
          "true",
          "false"
      ]
    }
```

Update the Region-stack resource in the Root-stack template- add _VPCPeeringCreate_ parameter to be passed to the Root-stack template:

```
"Resources": {

    "RegionNetworkStack": {
      "Type": "AWS::CloudFormation::Stack",
      "Properties": {
        "TemplateURL": "eks-region-networking.json",
        "Parameters": {
          "VPCCIDRBlock": { "Ref": "VPCCIDRBlock" },
          "VPCPeeringCreate": { "Ref": "VPCPeeringCreate"}
        }
      }
    },
...
```

#### Region Stack

Will accept the _VPCPeeringCreate_  —  remove the default value here as it will be passed from the Root-stack:

```
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "AWS CloudFormation Region Networking stack for Kubernetes cluster",

  "Parameters" : {
...

    "VPCPeeringCreate": {
      "Description": "Create or not VPC peering connections",
      "Type": "String",
      "AllowedValues": [
          "true",
          "false"
      ]
    }
  },
...
```

#### Conditions

Now — the main part here: add the Conditions called _DoVPCPeeringCreate_ where we will check the _VPCPeeringCreate_'s value using [Fn::Equals](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-equals) and if it's _true_ - then return _true_ from the Condition:

```
...
    "VPCPeeringCreate": {
      "Description": "Create or not VPC peering connections",
      "Type": "String",
      "AllowedValues": [
          "true",
          "false"
      ]
    }
  },

  "Conditions" : {
    "DoVPCPeeringCreate" : {"Fn::Equals" : [{"Ref" : "VPCPeeringCreate"}, true] }
  },

...
```

Next, add a check for both _MonitoringProdVPCPeeringConnection_ and _MonitoringToEksProdPeeringRoute_ resources — "Condition" : "DoVPCPeeringCreate":

```
...
    "MonitoringProdVPCPeeringConnection": {
      "Type": "AWS::EC2::VPCPeeringConnection",
      "Condition" : "DoVPCPeeringCreate",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "PeerVpcId": { "Fn::ImportValue" : "monitoring-production-VPC-ID" },
        "PeerRegion": { "Fn::ImportValue" : "monitoring-production-StackRegion" },
        "Tags": [
          {
            "Key": "Name",
            "Value": { "Fn::Join": ["-", [ {"Ref": "AWS::StackName"}, "vpc-monitoring-prod"] ] }
          }
        ]
      }
    },

    "MonitoringToEksProdPeeringRoute": {
      "Type": "AWS::EC2::Route",
      "Condition" : "DoVPCPeeringCreate",
      "Properties": {
        "RouteTableId": { "Fn::ImportValue" : "monitoring-production-VPC-PublicRouteTable" },
        "DestinationCidrBlock": { "Ref": "VPCCIDRBlock" },
        "VpcPeeringConnectionId": {
          "Ref": "MonitoringProdVPCPeeringConnection"
        }
      }
    },
...
```

So, if the _DoVPCPeeringCreate_ Condition will return _True_ - then the _MonitoringProdVPCPeeringConnection_ and _MonitoringToEksProdPeeringRoute_ resources will be triggered for creation.

Run to check — and here they are created:

![](https://cdn-images-1.medium.com/max/1024/0*-RovGmoIRvUdzc-E.png)

#### _Unresolved resource dependencies_ and Fn::If

And now — run the same but at this time specify the _VPCPeeringCreate_ == _false_, and you’ll get an error because of missing value in the Outputs on th Region-stack:

![](https://cdn-images-1.medium.com/max/1024/0*EZ1R3vc8UXZRSueV.png)

Why so? Well — because we’ve disabled the peering to be created, but in the Region-stack’s Outpus we still trying to put an ID of the peering which wasn't created:

```
...
    "MonitoringProdVPCPeeringConnectionID": {
      "Description" : "MonitoringProdVPCPeeringConnection ID",
      "Value" : {"Ref" : "MonitoringProdVPCPeeringConnection" }
    }
...
```

To resolve this — update the Outputs and use the [Fn::If](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if) to chose what exactly to return:

```
...
  "Outputs" : {

    "VPCID" : {
      "Description" : "EKS VPC ID",
      "Value" : { "Ref" : "VPC" }
    },

    "IGWID" : {
      "Description" : "InternetGateway ID",
      "Value" : { "Ref" : "InternetGateway" }
    },

    "MonitoringProdVPCPeeringConnectionID": {
      "Description" : "MonitoringProdVPCPeeringConnection ID",
      "Value" : { "Fn::If" : ["DoVPCPeeringCreate", {"Ref" : "MonitoringProdVPCPeeringConnection" }, "Zero"] }
    }

  }
}
...
```

I.e. if the DoVPCPeeringCreate Condition will return _True_ - then we will grab the _MonitoringProdVPCPeeringConnection's_ ID and will put to the, if DoVPCPeeringCreate == _false_ - then in the Outputs we will put some other value, here is for example "Zero".

#### AvailabilityZones stack

And in the AZ-stack we need to do the same things — add the parameter and add the Conditions - copy-past it from the Region-stack, and create a check for the AWS::EC2::Route resource - "Condition" : "DoVPCPeeringCreate":

```
...
    "EksToMonitoringProdPeeringRoute": {
      "Type": "AWS::EC2::Route",
      "Condition" : "DoVPCPeeringCreate",
      "Properties": {
        "RouteTableId": {
          "Ref": "PrivateRouteTable"
        },
        "DestinationCidrBlock": {
          "Fn::ImportValue" : "monitoring-production-VPC-CIDR"
        },
        "VpcPeeringConnectionId": {
          "Ref": "MonitoringProdVPCPeeringConnectionID"
        }
      }
    },
...
```

In the Root-стеке add the _VPCPeeringCreate_ to be passed to the AZ-stack:

```
...
    "AZNetworkStackA": {
      "Type": "AWS::CloudFormation::Stack",
      "Properties": {
        "TemplateURL": "eks-azs-networking.json",
        "Parameters": {
          "VPCID": { "Fn::GetAtt": ["RegionNetworkStack", "Outputs.VPCID"] },
          "AZ": { "Fn::Select": ["0", { "Ref": "AvailabilityZones" }] },
          "IGWID": { "Fn::GetAtt": ["RegionNetworkStack", "Outputs.IGWID"] },
          "VPCPeeringCreate": { "Ref": "VPCPeeringCreate"},
...
```

Create stacks — and no peering created:

![](https://cdn-images-1.medium.com/max/1024/0*S-1E8RjX-jEeGDB7.png)

To check — create again, with the _VPCPeeringCreate == true:_

![](https://cdn-images-1.medium.com/max/1024/0*bMPE-wiz5WKf-saQ.png)

Done.

_Originally published at_ [_RTFM: Linux, DevOps and system administration_](https://rtfm.co.ua/en/aws-cloudformation-using-conditions-fnequals-and-fnif-an-example/)_._

* * *