AWS::NoValue on CloudFormation: Conditional Property Configuration

Defining Resource Properties Conditionally Using AWS::NoValue on CloudFormation

AWS CloudFormation provides a handful of pseudo parameters which you can use along with your template conditions and parameters to increase the reusability of your templates. One of them is the AWS::NoValue parameter which acts as the null value in programming languages.

In this post, I will talk about some examples of its use cases.

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 the AWS::NoValue pseudo parameter, it simply returns null. Hence, you can use this pseudo parameter to configure a resource property conditionally. For instance, it becomes convenient if you want to use the same template to create an RDS instance with or without using an Amazon RDS snapshot.

Similarly, you can use the AWS::NoValue parameter to conditionally attach a security group to an Amazon EC2 instance. 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 some sample templates in YAML for both examples.

Examples

Using AWS::NoValue to provide DB snapshots during RDS instance creation

So, one popular example is creating an Amazon RDS instance from a DB snapshot if the DB snapshot is provided as a parameter during the stack creation. But to achieve this, we need to add another parameter to choose to use a snapshot. Unfortunately, there is no feature to directly test whether a parameter is provided yet. Hence, we cannot compare a parameter value with the null value at this time.

So we will 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 also need parameters for the master username and password of the RDS instance. Then we need a condition to check whether the UseSnapshot parameter is true. We can do this as below.

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

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

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

Here, if UseSnapshotSelected evaluates to false, referencing AWS::NoValue will make the DBSnapshotIdentifier property undefined under the RDS instance resource.

Besides, if we referenced the DbSnapshot parameter directly, without using any condition, the stack creation would fail when we provided it empty. But now, we can leave the DbSnapshot parameter blank, select the UseSnapshot parameter as false and continue.

So the final sample template will be as 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 its value is production.

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

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

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

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

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 the AWS::NoValue pseudo parameter along with conditions and the intrinsic Fn::If function to define resource attributes conditionally. I added 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 AWS resources, I launched beginner and advanced level courses on Udemy. We cover conditions and pseudo parameters in the beginner-level course, and we have a similar example of using the AWS::NoValue pseudo parameter in one of the section activities. Please see the links below if you are interested.

Thanks for reading!

Would you like to learn AWS CloudFormation?

If you would like to learn AWS CloudFormation to manage your infrastructure as code and automate the provisioning of your AWS resources, I would be happy to help you with my courses on Udemy. I divided the topics into two courses according to your knowledge level.

If you are a beginner to AWS CloudFormation, AWS CloudFormation Step by Step: Beginner to Intermediate will teach you its basics and most of the associate-level features. After finishing it, or if you know all those topics, you can enroll in my next-level CloudFormation course, AWS CloudFormation Step by Step: Intermediate to Advanced, which covers more advanced, professional-level features.

Besides, for all my available courses, please check out our Online Courses page. Hope to see you in them!

References

Emre Yilmaz

AWS Consultant • Instructor • Founder @ Shikisoft

Follow