Using Functions & Pseudo Parameters
This tutorial references the code in the aws-connectedcar-dotnet-serverless repository. If you're new to this course, see the introduction for information about setting up your workstation and getting the sample code.
This tutorial covers the three intrinsic functions that you’ll use most frequently in CloudFormation templates. These are: the !Ref function that lets you reference default resource attribute values in templates; the !GetAtt function that lets you reference other, named resource attribute values; and the !Sub function that performs basic string interpolation. There are additional functions that you’ll eventually want to learn. But these are the ones that are essential when first writing CloudFormation templates.
For documentation on all the available intrinsic functions see:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
About Resource Identifiers
We need to briefly highlight the fact that AWS has a number of different ways to identify resources, which affects how you use these functions. Many resources support user-defined names, which have to be unique within an AWS region and for an account. AWS also uses Amazon Resource Names (ARN) as a global namespace to identify resources. These consist of colon-separated elements that specify the resource type, region, account, and resource identifier elements. Then there are other resources, often network-related, that don't have user-defined names of any kind. When you declare a network subnet, for example, you don't define a name for it. Instead, it’s identified by a generated ID. API Gateway APIs are an example of a resource type that does have a user-defined name but is generally referenced in CloudFormation or from the command-line by its generated API ID.
So be aware going forward that the resources that you declare in CloudFormation often include references to other resources. For those referenced resources that have generated IDs, that will usually be the value you’ll need to assign. For resources that have user-defined names, it will usually be ARN values that you need to assign.
About Function Syntax
Another fact to highlight is that there are two different syntaxes you can use with intrinsic functions. Using the reference function as an example, there’s a long-form syntax that takes the form of Fn::Ref and a short-form syntax that takes the form of !Ref. Be aware that for content that’s included inline within a template using the Transform::Include feature, such as OpenAPI documents, you must use the long form (we’ll show examples for this in the section on API Gateway). Otherwise, the sample code for this course always uses the more concise, short form syntax.
Using the !Ref Function
Now, to see examples for our first function, let’s look at the roles.yaml template from the SAM version of the sample code. This template defines two security resources: an IAM policy for logging, and a service role that grants access for logging based on this policy. The definitions for these two resources plus the template output are shown below:
Lines 47 and 48 in the code above show the use of the !Ref function to return AWS resource names (ARN) for the referenced items. In the first case, the LoggingPolicy resource that’s defined above is referenced by the !Ref function. The default value returned by the !Ref function for this resource is the ARN. In the second case, the !Ref function references the ServicesPolicyArn input parameter. Here the value returned is simply the string value of the parameter, which also happens to be an ARN.
Using the !GetAtt Function
The !Ref function always returns the value for the default attribute of a resource. But sometimes you need the value for a different resource attribute. In these cases you can, if the attribute is available to it, use the !GetAtt function. You can see an example where this function is used in lines 57-59 in the code above. This function is used here because while the default value for the AWS::IAM::ManagedPolicy type is the ARN, for the related AWS::IAM::Role type the default value is actually the user-defined resource name, not the full ARN. So the !GetAtt function is used to specify the resource by name, on line 58 (the LambdaExecutionRole), and this resource’s ARN as the attribute to be returned, on line 59.
As this small code sample demonstrates, you have to consult the CloudFormation documentation for any given resource type to know what value the !Ref function returns and what attributes are available with the !GetAtt function. Here’s a screenshot of this documentation for the AWS::IAM::Role type, showing what’s available with these two functions:
Using the !Sub Function
An example of the !Sub function can be seen on line 51, from the code sample shown above, which looks like this:
RoleName: !Sub '${ServiceName}LambdaExecutionRole${EnvironmentName}'
As you can tell from the syntax, the !Sub function performs simple string interpolation similar to what you see in scripting languages. This is a function that you use constantly when writing CloudFormation templates. The example above also shows how we’re defining segmented resource names that are unique to a CloudFormation stack, using the ServiceName and EnvironmentName values. These values are both defined as input parameters in the template (more on this in the next tutorial). In the templates in the sample code you’ll also see this function used to construct things like URLs for S3 buckets, wild-carded resource ARNs for IAM policies, and values for the environment variables that are used by Lambdas.
Using Pseudo Parameters
Pseudo parameters provide access during execution to ambient AWS properties such as the current account ID or the region name. Here’s an example from the roles.yaml template, which we looked at in the previous tutorial:
On line 33 in the code above, the !Sub function constructs a wild-carded ARN that defines the resources that apply for the IAM policy. Here, both the AWS::Region and the AWS::AccountId pseudo parameters are used. There are many other cases where you’ll use these pseudo parameters in the same way. Here’s another example from the master.yaml template where the !Sub function, on line 35, constructs an S3 URL using the AWS::Region pseudo parameter:
These parameters are so useful precisely because ARNs and many AWS URLs incorporate region and/or account ID values.