Defining Resource Properties Conditionally Using AWS::NoValue on CloudFormation

  • by Emre Yilmaz
  • Jun 20, 2019
  • AWS, DevOps
  • Istanbul
Defining Resource Properties Conditionally Using AWS::NoValue on CloudFormation

AWS CloudFormation provides handful pseudo parameters which you can use to increase the reusability of your templates along with your template conditions and parameters. One of them is AWS::NoValue parameter which acts like the null value in programming languages. In this post I will make some examples of its use cases.

By the way, if you are a beginner to AWS CloudFormation and you would like to learn it, please check out our new course on Udemy. You can join us with up to 90% discount using this link: AWS CloudFormation Step by Step: Beginner to Intermediate. We will be happy to see you there, too!

Now let’s continue this blog post and start with what a pseudo parameter is.

What is a pseudo parameter?

Firstly, let’s talk about the pseudo parameters on AWS CloudFormation. As you know, you can define parameters in your templates as configurable variables while creating or updating your stacks. AWS provides additional variables like the AWS region you launch the stack, AWS::Region, or the stack ID of your stack, AWS::StackId, to get them dynamically during the stack creation or update.

You can reference these parameters using the intrinsic ref function from the Resources section in your templates. For instance, AWS::Region and AWS::AccountId are really handy when constructing Amazon Resource Names (ARNs) when you need them.

Hence, AWS::NoValue is one of these pseudo parameters.

What is AWS::NoValue used for?

When you reference AWS::NoValue pseudo parameter, it simply returns null. So you can use this pseudo parameter to configure a resource property conditionally. For instance, it becomes very handy when you would like to use the same template to create an RDS instance with or without using an Amazon RDS snapshot.

Similarly, you can use AWS::NoValue parameter to attach a security group to an Amazon EC2 instance conditionally. For example, you may need to attach a security group to the instance only in your development environment by using this pseudo parameter with a condition and a parameter.

Now I will show you sample templates in YAML for both examples.

Examples

Using AWS::NoValue to provide DB snapshots

One popular example is creating an RDS instance from a DB snapshot if the db snapshot provided as a parameter. But we need to add another parameter to choose to use a snapshot. Unfortunately, there is not feature to test whether a parameter is provided yet. We cannot compare a paramater value with null value.

So we have two parameters for this in the example template below:

  • DbSnapshot: The name or ARN name of the DB snapshot.
  • UseSnapshot: A parameter to select the option to use a snapshot while creating the DB instance.
AWSTemplateFormatVersion: 2010-09-09
Description: Conditionally creating db instance from a db snapshot.
Parameters:
  DbSnapshot:
    Type: String
  UseSnapshot:
    Type: String
    AllowedValues: [ true, false ]

We will need parameters for master username and password of the RDS instance, too. Then we need a condition to check whether UseSnapshot parameter is true. We can do this as below.

...
Conditions:
  UseSnapshotSelected: !Equals [ !Ref UseSnapshot, 'true' ]
...

Next, we will use this condition with the intrisic Fn::If function to provide the DbSnapshot value if UseSnapshotSelected evaluates to true. Otherwise, we will reference AWS::NoValue parameter and it will return null.

        ...
        DBSnapshotIdentifier: !If [ UseSnapshotSelected, !Ref DbSnapshot, !Ref 'AWS::NoValue' ]
        ...

Here referencing AWS::NoValue will mean not to define the DBSnapshotIdentifier identifier property at all. If we referenced DbSnapshot property without any condition, the stack creation would fail if we do not provide a db snapshot. But now, we can leave DbSnapshot parameter blank and select UseSnapshot false and continue.

So the whole example template becomes like the one below.

AWSTemplateFormatVersion: 2010-09-09
Description: Conditionally creating db instance from a db snapshot.
Parameters:
  DbSnapshot:
    Type: String
  UseSnapshot:
    Type: String
    AllowedValues: [ true, false ]
  MasterUsername:
    Type: String
  MasterUserPassword:
    Type: String
Conditions:
  UseSnapshotSelected: !Equals [ !Ref UseSnapshot, 'true' ]
Resources:
  DbInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: 20
      DBInstanceClass: db.t2.micro
      Engine: mysql
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      DBSnapshotIdentifier: !If [ UseSnapshotSelected, !Ref DbSnapshot, !Ref 'AWS::NoValue' ]

Using AWS::NoValue to attach a security group to an EC2 instance conditionally

Another example is attaching a security group to an EC2 instance only in our production environment. This time we will need only one parameter for the environment name and a condition to test whether it is production.

Parameters:
    EnvironmentName:
        Type: String
        AllowedValues: [ test, production ]
...
Conditions:
    EnvironmentIsProduction:    !Equals [ !Ref EnvironmentName, `production` ]
...

Then we can use this condition to attach a security group to an EC2 instance conditionally like this.

Parameters:
    EnvironmentName:
        Type: String
        AllowedValues: [ test, production ]
...
Conditions:
    EnvironmentIsProduction:  !Equals [ !Ref EnvironmentName, `production` ]
...

Then we can attach a security group to an EC2 instance only if the environment is production as below.

Resources:
    SecurityGroup:
        Type: AWS::EC2::SecurityGroup
    ...
  ...
    SampleInstance:
        Type: AWS::EC2::Instance
        Properties:
            ...
            SecurityGroupIds:
              - !If [ EnvironmentIsProduction, !Ref SecurityGroup, !Ref 'AWS::NoValue' ]
  ...

So if environment is not production, SecurityGroupIds property will not be defined at all. If we don’t use conditions, Fn::If function and AWS::NoValue pseudo parameter, we had to create two similar templates to manage this difference between our environments.

You can find the template for the second example in full below.

AWSTemplateFormatVersion: 2010-09-09
Description: Conditionally creating attaching a security group to an EC2 instance.
Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
  WebServerSubnet:
    Type: AWS::EC2::Subnet::Id
  ImageId:
    Type: String
  EnvironmentName:
    Type: String
    AllowedValues: [ test, production ]
Conditions:
  EnvironmentIsProduction: !Equals [ !Ref EnvironmentName, 'production' ]
Resources:
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group to allow SSH access
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        -
          CidrIp: 0.0.0.0/0
          IpProtocol: tcp
          FromPort: 22
          ToPort: 22

  SampleInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SubnetId: !Ref WebServerSubnet
      ImageId: !Ref ImageId
      SecurityGroupIds:
        - !If [ EnvironmentIsProduction, !Ref SecurityGroup, !Ref 'AWS::NoValue' ]

Conclusion

This is how to use AWS::NoValue pseudo parameter along with conditions and the intrinsic Fn::If function to define resource attributes conditionally. I added to examples to demonstrate this, but I am sure that you will customize them as you like according to your needs.

By the way, if you would like to learn AWS CloudFormation to manage your infrastructure as code and automate the provisioning of your resources on AWS, recently I launched a new course on Udemy. You can check my blog posts or links on this page to get your coupon code with a discount. I will be happy to see you there.

If you liked this post, you can share it on LinkedIn and Twitter using the buttons at the top. Please feel free to connect with / follow me on Linkedn and Twitter as well. I will be happy to meet you.

Thanks for reading!

References

...

Freelance AWS Consultant, Instructor

CEO @ Shikisoft

Follow

Would you like to learn AWS CloudFormation?

Our new course AWS CloudFormation Step by Step: Beginner to Intermediate is live on Udemy!

Join us now with up to 90% discount using the coupon below!

Enroll now!
RSS

Subscribe to this blog's RSS feed

Categories