DEV Community

Cover image for Hands-on AWS CloudFormation - Part 2. Into to Intrinsic functions
Samira Yusifova
Samira Yusifova

Posted on

Hands-on AWS CloudFormation - Part 2. Into to Intrinsic functions

This is Part 2 of Hands-on AWS CloudFormation series, you can find Part 1 here.

This article will walk you through the basic Intrinsic functions of AWS CloudFormation, which are simply built-in functions that can help you manage your stacks.

Fn::Ref

What if you need to use dynamically generated values, the values that are required but are only available at run time? For example, let’s say that you need to create a new VPC and a new Security group in the same stack; and you need to pass VPC's ID to Security group. Here is how you can do that:

 Resources: mySecurityGroup: # Logical ID Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: My description here VpcId: Ref: myVPC # ref to VPC that will be created by CloudFormation # etc.  myVPC: # Logical ID Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 # etc.  
Enter fullscreen mode Exit fullscreen mode

Another way to use Ref is with Parameters. Let’s say that you need to create a new EC2 instance and you need to pass EC2 key pairs and instance’s tag during a stack creation.

 Parameters: paramTagValue: # declare paramTagValue as a parameter Description: Value of tag for EC2 instance Type: String paramKeyName: # declare paramKeyName as a parameter Description: Name of an existing EC2 KeyPair to enable SSH access into the server Type: 'AWS::EC2::KeyPair::KeyName' Resources: myEc2Instance: # Logical ID Type: 'AWS::EC2::Instance' Properties: InstanceType: t2.micro ImageId: ami-5b41123e Tags: - Key: CloudFormationLab Value: !Ref paramTagValue # ref to Parameters KeyName: !Ref paramKeyName # ref to Parameters 
Enter fullscreen mode Exit fullscreen mode

Note, that Parameters allow you to pass user inputs at the time of stack creation or update (it will be discussed in the next parts of the series).

The third way to use Ref is as a pseudo parameter. Pseudo parameters are parameters that are predefined by AWS CloudFormation. For example, what if you need to get a region where your resources are being created, e.g. us-west-1? In that case use AWS::Region:

 Tags: - Key: CloudFormationLab Value: !Ref AWS::Region # use pseudo parameter to get a region 
Enter fullscreen mode Exit fullscreen mode

Other pseudo parameters:

  • AWS::AccountId (returns AWS account ID of the account in which the stack is being created)
  • AWS::StackId (returns arn name of the stack)
  • AWS::StackName (returns friendly name of the stack)
  • AWS::NoValue (acts like the null value)

See the whole list by vising AWS's Pseudo parameters reference documentation.

Fn::Select

Select allows you to select one item from a list. Assume that you have a list of CIDR blocks and you need to create three subnets by passing the first CIDR block to the first subnet, the second CIDR block to the second subnet, so on. Here is how you can do that:

 Parameters: paramDbSubnetIpBlocks: Description: 'Comma-delimited list of three CIDR blocks' Type: CommaDelimitedList Default: '10.0.48.0/24, 10.0.112.0/24, 10.0.176.0/24' Resources: myFirstSubnet: # Logical ID Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref myVPC CidrBlock: !Select [ 0, !Ref paramDbSubnetIpBlocks ] # output is 10.0.48.0/24 # etc.  mySecondSubnet: # Logical ID Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref myVPC CidrBlock: !Select [ 1, !Ref paramDbSubnetIpBlocks ] # output is 10.0.112.0/24 # etc. myVPC: Type: 'AWS::EC2::VPC' Properties: # etc 
Enter fullscreen mode Exit fullscreen mode

Fn::Join

With Join you can take a set of values and append it into a single value, separated by the specified delimiter. Here is an example:

 Tags: - Key: CloudFormationLab Value: !Join [ ' ', [ 'SecurityGroup', 'for', !Ref AWS::Region ] ] # Output is “SecurityGroup for us-west-1” 
Enter fullscreen mode Exit fullscreen mode

Fn::Split

Split is the opposite of Join. It splits a string into a list of string values. Commonly used with Select. Assume that the parameter's value is a comma-delimited string instead of list. You can still easily convert this string into a list.

 Parameters: paramDbSubnetIpBlocks: Description: 'Comma-delimited string of three CIDR blocks' Type: CommaDelimitedList Default: '10.0.48.0/24, 10.0.112.0/24, 10.0.176.0/24' Resources: myFirstSubnet: # Logical ID Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: !Select [ 0, !Split [',', !Ref paramDbSubnetIpBlocks]] # output is 10.0.48.0/24 # etc.  mySecondSubnet: # Logical ID Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: !Select [ 1, !Split [',', !Ref paramDbSubnetIpBlocks]] # output is 10.0.112.0/24 # etc. 
Enter fullscreen mode Exit fullscreen mode

Fn::GetAtt

What if you need to get an Availability Zone of your EC2 instance specified in your template? Or maybe public DNS? Well, you can use GetAtt which returns the value of an attribute from a resource in the template.

 Resources: myEC2Instance: # Logical ID Type: 'AWS::EC2::Instance' # etc.  MountPoint: # etc.  myInstanceVolume: # Logical ID Type: 'AWS::EC2::Volume' Properties: Size: 100 AvailabilityZone: !GetAtt myEC2Instance.AvailabilityZone # use GetAtt to get AZ of your EC2 instance Outputs: PublicDNS: Description: EC2 instance public DNS name Value: !GetAtt myEC2Instance.PublicDnsName # use GetAtt to get public DNS of your EC2 instance 
Enter fullscreen mode Exit fullscreen mode

Note, that Outputs allow you to declare output values that you can return in response to view on console or import into other stacks (it will be discussed in the next parts of the series).

But how would you know which attributes each resource has? You need to navigate to AWS CloudFormation's documentation and search for
"AWS resource and property types reference". Find a target resource from the list, e.g. EC2, then search by resource types, e.g. AWS::EC2::Instance. Scroll down and look for "Return values" section. Under "Fn::GetAtt" you can find the list of all available attributes for selected resource type:

Alt Text

Fn::GetAZs

You don't want to hard-code a full list of AZs for a specified region, do you? In that case use GetAZs. It returns a list of AZs for a target region in alphabetical order.

 !GetAZs us-east-1 # output is [ 'us-east-1a', 'us-east-1b', 'us-east-1c', 'us-east-1d' ] 
Enter fullscreen mode Exit fullscreen mode

You can use GetAZs with Ref and Select:

 Resources: myInstanceVolume: # Logical ID Type: 'AWS::EC2::Volume' Properties: Size: 100 AvailabilityZone: !Select [0, !GetAZs !Ref 'AWS::Region'] # !Ref 'AWS::Region' returns a region where your volume is being created, e.g. us-east-1  # !GetAZs 'us-east-1' returns the list of AZs for 'us-east-1' region, which are ['us-east-1a', 'us-east-1b', 'us-east-1c', 'us-east-1d'] # !Select ['us-east-1a', 'us-east-1b', 'us-east-1c', 'us-east-1d'] returns the first value from the list, which is 'us-east-1a' 
Enter fullscreen mode Exit fullscreen mode

Fn::FindInMap

Let's start with Mappings. Why would you need it? Let’s say that you want to provision a new EC2 instance and you want to specify image ID (AMI) based on a region where your instance is being created. E.g. for North Virginia ('us-east-1') region you need to use 'ami-1853ac65' image id and for Singapore ('ap-southeast-1') - 'ami-e2adf99e'. In this case you can use Mappings which allows you to create simple "key:value" dictionaries for use in your resource declarations.

 Mappings: # map image ids with regions mapRegion: us-east-1: AMI: ami-1853ac65 us-west-1: AMI: ami-bf5540df eu-west-1: AMI: ami-3bfab942 ap-southeast-1: AMI: ami-e2adf99e ap-southeast-2: AMI: ami-43874721 
Enter fullscreen mode Exit fullscreen mode

Now, in order to call your map and get a value based on a key, you need to use FindInMap function:

 

Mappings: # map image ids with regions
mapRegion:
us-east-1:
AMI: ami-1853ac65
us-west-1:
AMI: ami-bf5540df
# etc.
Resources:
myEc2Instance: # Logical ID
Type: 'AWS::EC2::Instance'
Properties:
InstanceType: t2.micro
ImageId: !FindInMap # define imageId based on region
- mapRegion # map's name
- !Ref 'AWS::Region' # top level key which is a region where your instance is being created
- AMI # second level key - e.g. for 'us-east-1' the value for ImageId is 'ami-1853ac65'

Enter fullscreen mode Exit fullscreen mode




Other intrinsic functions

Alt Text

Now, that was a whole lot to cover but if you read it, kudos! So far we have covered the most crucial intrinsic functions. The rest might be discussed later, here is a brief list:

  • Fn::Base64 - returns the Base64 representation of the input string (details)
  • Fn::Cidr - returns an array of CIDR address blocks (details)
  • Fn::ImportValue - returns the value of an output exported by another stack (details)
  • Fn::Sub - substitutes variables in an input string with values that you specify (details)
  • Fn::Transform - specifies a macro to perform custom processing on part of a stack template (details)

Conclusion

Intrinsic (i.e. build-in) functions are extremely useful and efficient if you'd like to start writing your templates. There is one more group of intrinsic functions left, named Condition functions, which I’m going to cover in Part 3 of Hands-on AWS CloudFormation series. Once we are done with functions we can start using them in custom templates.

Top comments (0)