This is Part 2 of Hands-on AWS CloudFormation series.
- Hands-on AWS CloudFormation – Part 1. It All Starts Here
- Hands-on AWS CloudFormation – Part 2. Into to Intrinsic functions
- Hands-on AWS CloudFormation – Part 3. Intrinsic functions in Action
- Hands-on AWS CloudFormation – Part 4. Create VPC with private and public subnets
- Hands-on AWS CloudFormation – Part 5. IAM users, groups and roles
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.
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
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
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
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”
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.
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
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:

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' ]
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'
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
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'
Other intrinsic functions

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.