Templates overview
This topic provides an introduction to the key parts of a template and how to use them.
You can use the sections on this page to learn the following about templates:
-
Declaring resources and their properties.
-
Referencing other resources with the
Ref
function and resource attributes using theFn::GetAtt
function. -
Using parameters to specify values at stack creation time and using constraints to validate parameter input.
-
Using mappings to determine conditional values.
-
Using the
Fn::Join
function to construct values based on parameters, resource attributes, and other strings. -
Using output values to capture information about the stack's resources.
Topics
About templates
A CloudFormation template is a declaration of the Amazon resources that make up a stack. The template is a text file that follows specific formatting rules using either the JavaScript Object Notation (JSON) or YAML standard. Because templates are text files, you can create and edit them in any text editor and manage them in your source control system with the rest of your source code.
In the template, you declare the Amazon resources that you want to create. You define each resource as a set of properties and values using the syntax rules of the chosen format (JSON or YAML).
Templates have different sections, but the only required section is the
Resources
section, which must declare at least one resource.
For examples that show the complete structure of a template with all available sections, see Template formats. For a list of resources that you can create with CloudFormation, see Amazon resource and property types reference.
Resources: Hello Bucket!
The Resources
section is a list of the resources you want to create. Each
resource must have a Type
attribute, which defines the kind of Amazon resource it
is. The Type
attribute has a special format:
AWS::
ProductIdentifier
::ResourceType
For example, the resource type for an Amazon S3 bucket is AWS::S3::Bucket
.
Let's take a look at a basic template. The following template declares a single resource
of type AWS::S3::Bucket:
with the name HelloBucket
.
JSON
{ "Resources": { "HelloBucket": { "Type": "AWS::S3::Bucket" } } }
YAML
Resources: HelloBucket: Type: 'AWS::S3::Bucket'
If you use this template to create a stack, CloudFormation will create an Amazon S3 bucket.
Creating a bucket is simple, because CloudFormation can create a bucket with default settings. For
other resources, such as an Amazon EC2 instance or Auto Scaling group, CloudFormation requires more
information. Resource declarations use a Properties
attribute to specify the
information used to create a resource.
Depending on the resource type, some properties are required, such as the
ImageId
property for an AWS::EC2::Instance
resource, and others
are optional. Some properties have default values, such as the AccessControl
property of the AWS::S3::Bucket
resource, so specifying a value for those
properties is optional. Other properties aren't required but may add functionality that you
want, such as the WebsiteConfiguration
property of the
AWS::S3::Bucket
resource. Specifying a value for such properties is entirely
optional and based on your needs. In the example above, because the
AWS::S3::Bucket
resource has only optional properties and we didn't need any of
the optional features, we could accept the defaults and omit the Properties attribute.
To view the properties for each resource type, see the topics in Amazon resource and property types reference.
Resource properties and using resources together
Usually, a property for a resource is simply a string value. For example, the following
template specifies a canned ACL (PublicRead) for the AccessControl
property of
the bucket.
JSON
{ "Resources": { "HelloBucket": { "Type": "AWS::S3::Bucket", "Properties": { "AccessControl": "PublicRead" } } } }
YAML
Resources: HelloBucket: Type: 'AWS::S3::Bucket' Properties: AccessControl: PublicRead
Some resources can have multiple properties, and some properties can have one or more
subproperties. For example, the AWS::S3::Bucket
resource has two properties:
AccessControl
and WebsiteConfiguration
. The
WebsiteConfiguration
property has two subproperties: IndexDocument
and ErrorDocument
. The following template shows our original bucket resource with
the additional properties.
JSON
{ "Resources": { "HelloBucket": { "Type": "AWS::S3::Bucket", "Properties": { "AccessControl": "PublicRead", "WebsiteConfiguration": { "IndexDocument": "index.html", "ErrorDocument": "error.html" } } } } }
YAML
Resources: HelloBucket: Type: 'AWS::S3::Bucket' Properties: AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html ErrorDocument: error.html
One of the greatest benefits of templates and CloudFormation is the ability to create a set of resources that work together to create an application or solution. The name used for a resource within the template is a logical name. When CloudFormation creates the resource, it generates a physical name that's based on the combination of the logical name, the stack name, and a unique ID.
You're probably wondering how you set properties on one resource based on the name or
property of another resource. For example, you can create a CloudFront distribution backed by an S3
bucket or an EC2 instance that uses EC2 security groups, and all of these resources can be
created in the same template. CloudFormation has a number of intrinsic functions that you can use
to refer to other resources and their properties. You can use the Ref
function to
refer to an identifying property of a resource. Frequently, this is the physical name of the
resource; however, sometimes it can be an identifier, such as the IP address for an
AWS::EC2::EIP
resource or an Amazon Resource Name (ARN) for an Amazon SNS topic. For
a list of values returned by the Ref
function, see Ref function. The following template
contains an AWS::EC2::Instance
resource. The resource's
SecurityGroups
property calls the Ref
function to refer to the
AWS::EC2::SecurityGroup
resource InstanceSecurityGroup
.
JSON
{ "Resources": { "Ec2Instance": { "Type": "AWS::EC2::Instance", "Properties": { "SecurityGroups": [ { "Ref": "InstanceSecurityGroup" } ], "KeyName": "mykey", "ImageId": "" } }, "InstanceSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "Enable SSH access via port 22", "SecurityGroupIngress": [ { "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "CidrIp": "0.0.0.0/0" } ] } } } }
YAML
Resources: Ec2Instance: Type: 'AWS::EC2::Instance' Properties: SecurityGroups: - !Ref InstanceSecurityGroup KeyName: mykey ImageId: '' InstanceSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Enable SSH access via port 22 SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0
The SecurityGroups
property is a list of security groups, and in the previous
example we have only one item in the list. The following template has an additional item in
the SecurityGroups
property list.
JSON
{ "Resources": { "Ec2Instance": { "Type": "AWS::EC2::Instance", "Properties": { "SecurityGroups": [ { "Ref": "InstanceSecurityGroup" }, "MyExistingSecurityGroup" ], "KeyName": "mykey", "ImageId": "ami-7a11e213" } }, "InstanceSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "Enable SSH access via port 22", "SecurityGroupIngress": [ { "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "CidrIp": "0.0.0.0/0" } ] } } } }
YAML
Resources: Ec2Instance: Type: 'AWS::EC2::Instance' Properties: SecurityGroups: - !Ref InstanceSecurityGroup - MyExistingSecurityGroup KeyName: mykey ImageId: ami-7a11e213 InstanceSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Enable SSH access via port 22 SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0
MyExistingSecurityGroup
is a string that refers to an existing EC2 security
group instead of a security group declared in a template. You use literal strings to refer to
existing Amazon resources.
In the example above, the KeyName
property of the
AWS::EC2::Instance
is the literal string mykey
. This means that a
key pair with the name mykey must exist in the region where the stack is being created;
otherwise, stack creation will fail because the key pair doesn't exist. The key pair you use
can vary with the region where you are creating the stack, or you may want to share the
template with someone else so that they can use it with their Amazon Web Services account. If so, you can
use an input parameter so that the key pair name can be specified when the stack is created.
The Ref
function can refer to input parameters that are specified at stack
creation time. The following template adds a Parameters
section containing the
KeyName
parameter, which is used to specify the KeyName
property
for the AWS::EC2::Instance
resource. The parameter type is
AWS::EC2::KeyPair::KeyName
, which ensures a user specifies a valid key pair
name in his or her account and in the region where the stack is being created.
JSON
{ "Parameters": { "KeyName": { "Description": "The EC2 Key Pair to allow SSH access to the instance", "Type": "AWS::EC2::KeyPair::KeyName" } }, "Resources": { "Ec2Instance": { "Type": "AWS::EC2::Instance", "Properties": { "SecurityGroups": [ { "Ref": "InstanceSecurityGroup" }, "MyExistingSecurityGroup" ], "KeyName": { "Ref": "KeyName" }, "ImageId": "ami-7a11e213" } }, "InstanceSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "Enable SSH access via port 22", "SecurityGroupIngress": [ { "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "CidrIp": "0.0.0.0/0" } ] } } } }
YAML
Parameters: KeyName: Description: The EC2 Key Pair to allow SSH access to the instance Type: 'AWS::EC2::KeyPair::KeyName' Resources: Ec2Instance: Type: 'AWS::EC2::Instance' Properties: SecurityGroups: - !Ref InstanceSecurityGroup - MyExistingSecurityGroup KeyName: !Ref KeyName ImageId: ami-7a11e213 InstanceSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Enable SSH access via port 22 SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0
The Ref
function is handy if the parameter or the value returned for a
resource is exactly what you want; however, you may need other attributes of a resource. For
example, if you want to create a CloudFront distribution with an S3 origin, you need to specify the
bucket location by using a DNS-style address. A number of resources have additional attributes
whose values you can use in your template. To get these attributes, you use the Fn::GetAtt function. The following
template creates a CloudFront distribution resource that specifies the DNS name of an S3 bucket
resource using Fn::GetAtt
function to get the bucket's DomainName
attribute.
JSON
{ "Resources": { "myBucket": { "Type": "AWS::S3::Bucket" }, "myDistribution": { "Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { "Origins": [ { "DomainName": { "Fn::GetAtt": [ "myBucket", "DomainName" ] }, "Id": "myS3Origin", "S3OriginConfig": {} } ], "Enabled": "true", "DefaultCacheBehavior": { "TargetOriginId": "myS3Origin", "ForwardedValues": { "QueryString": "false" }, "ViewerProtocolPolicy": "allow-all" } } } } } }
YAML
Resources: myBucket: Type: 'AWS::S3::Bucket' myDistribution: Type: 'AWS::CloudFront::Distribution' Properties: DistributionConfig: Origins: - DomainName: !GetAtt - myBucket - DomainName Id: myS3Origin S3OriginConfig: {} Enabled: 'true' DefaultCacheBehavior: TargetOriginId: myS3Origin ForwardedValues: QueryString: 'false' ViewerProtocolPolicy: allow-all
The Fn::GetAtt
function takes two parameters, the logical name of the
resource and the name of the attribute to be retrieved. For a full list of available
attributes for resources, see Fn::GetAtt. You'll notice that the Fn::GetAtt
function lists its two
parameters in an array. For functions that take multiple parameters, you use an array to
specify their parameters.
Receiving user input using input parameters
So far, you've learned about resources and a little bit about how to use them together within a template. You've learned how to refer to input parameters, but we haven't gone deeply into how to define the input parameters themselves. Let's take a look at parameter declarations and how you can restrict and validate user input.
You declare parameters in a template's Parameters
section. A parameter
contains a list of attributes that define its value and constraints against its value. The
only required attribute is Type
, which can be String
,
Number
, or an Amazon-specific type. You can also add a Description
attribute that describes what kind of value you should specify. The parameter's name and
description appear in the Specify Parameters page when you use the
template in the Create Stack wizard.
The following template fragment is a Parameters
section that declares the
parameters used in the Specify Parameters page.
JSON
"Parameters": { "KeyName": { "Description" : "Name of an existing EC2 KeyPair to enable SSH access into the WordPress web server", "Type": "AWS::EC2::KeyPair::KeyName" }, "WordPressUser": { "Default": "admin", "NoEcho": "true", "Description" : "The WordPress database admin account user name", "Type": "String", "MinLength": "1", "MaxLength": "16", "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*" }, "WebServerPort": { "Default": "8888", "Description" : "TCP/IP port for the WordPress web server", "Type": "Number", "MinValue": "1", "MaxValue": "65535" } }
YAML
Parameters: KeyName: Description: Name of an existing EC2 KeyPair to enable SSH access into the WordPress web server Type: AWS::EC2::KeyPair::KeyName WordPressUser: Default: admin NoEcho: true Description: The WordPress database admin account user name Type: String MinLength: 1 MaxLength: 16 AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*" WebServerPort: Default: 8888 Description: TCP/IP port for the WordPress web server Type: Number MinValue: 1 MaxValue: 65535
For parameters with default values, CloudFormation uses the default values unless users specify another value. If you omit the default attribute, users are required to specify a value for that parameter; however, requiring the user to input a value does not ensure that the value is valid. To validate the value of a parameter, you can declare constraints or specify an Amazon-specific parameter type.
You'll notice that the KeyName
parameter has no Default
attribute and the other parameters do. For example, the WordPressUser
parameter
has the attribute Default: admin
, but the KeyName
parameter has
none. Users must specify a key name value at stack creation. If they don’t, CloudFormation fails
to create the stack and throws an exception:
Parameters: [KeyName] must have values
For Amazon-specific parameter types, CloudFormation validates input values against existing
values in the user's Amazon Web Services account and in the region where they're creating the stack
before creating any stack resources. In the sample template, the
KeyName
parameter is an Amazon-specific parameter type of
AWS::EC2::KeyPair::KeyName
. CloudFormation checks that users specify a valid EC2
key pair name before creating the stack. Another example of an Amazon-specific parameter type
is AWS::EC2::VPC::Id
, which requires users to specify a valid VPC ID. In addition
to upfront validation, the Amazon console shows a drop down list of valid values for
Amazon-specific parameter types, such as valid EC2 key pair names or VPC IDs, when users use
the Create Stack wizard.
For the String
type, you can use the following attributes to declare
constraints: MinLength
, MaxLength
, Default
,
AllowedValues
, and AllowedPattern
. In the example above, the
WordPressUser
parameter has three constraints: the parameter value must be 1 to
16 character long (MinLength
, MaxLength
) and must begin with a
letter followed by any combination of letters and numbers
(AllowedPattern
).
For the Number
type, you can declare the following constraints:
MinValue
, MaxValue
, Default
, and
AllowedValues
. A number can be an integer or a float value. In the example
above, the WebServerPort
parameter must be a number between 1 and 65535 inclusive
(MinValue
, MaxValue
).
Earlier in this section, we mentioned that parameters are a good way to specify sensitive
or implementation-specific data, such as passwords or user names, that you need to use but
don't want to embed in the template itself. If you set the NoEcho
attribute to
true
, CloudFormation returns the parameter value masked as asterisks (*****) for
any calls that describe the stack or stack events, except for information stored in the
locations specified below. In the example above, the WordPressUser
parameter
value isn't visible to anyone viewing the stack's settings, and its value is returned as
asterisks.
Important
Using the NoEcho
attribute does not mask any information stored in the following:
-
The
Metadata
template section. CloudFormation does not transform, modify, or redact any information you include in theMetadata
section. For more information, see Metadata. -
The
Outputs
template section. For more information, see Outputs. -
The
Metadata
attribute of a resource definition. For more information, see Metadata attribute.
We strongly recommend you do not use these mechanisms to include sensitive information, such as passwords or secrets.
Important
Rather than embedding sensitive information directly in your CloudFormation templates, we recommend you use dynamic parameters in the stack template to reference sensitive information that is stored and managed outside of CloudFormation, such as in the Amazon Systems Manager Parameter Store or Amazon Secrets Manager.
For more information, see the Do not embed credentials in your templates best practice.
Specifying conditional values using mappings
Parameters are a great way to specify unique or sensitive values for use in the properties of stack resources; however, there may be settings that are region dependent or are somewhat complex for users to figure out because of other conditions or dependencies. In these cases, you would want to put some logic in the template itself so that users can specify simpler values (or none at all) to get the results that they want.
For example, you might need a way to specify the right instance type based on a
conditional input (in this example, the region where the stack is created). There are two
template features that can help, the Mappings
section and the
AWS::Region
pseudo parameter.
The AWS::Region
pseudo parameter is a value that CloudFormation resolves as the
region where the stack is created. Pseudo parameters are resolved by CloudFormation when you
create the stack. With mappings, you can use an input value as a condition that determines
another value. Similar to a switch statement, a mapping associates one set of values with
another. Using the AWS::Region
parameter together with a mapping, you can ensure
that an instance type that's available in the region is specified. The following template
contains a Mappings
section with a mapping named RegionMap
that's
used to map an instance type to the appropriate region.
The following template also declares the
AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
parameter type. It
provides the Systems Manager parameter alias
(/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
) as the default
value for the ImageId
property of the EC2 instance. This is a value that
CloudFormation resolves as the AMI ID value for the latest Amazon Linux 2 AMI in the region where
the stack is created.
JSON
{ "Parameters": { "LatestAmiId": { "Description": "The latest Amazon Linux 2 AMI from the Parameter Store", "Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>", "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" } }, "Mappings": { "RegionMap": { "us-east-1": { "InstanceType": "t2.micro" }, "us-west-1": { "InstanceType": "t2.micro" }, "eu-west-1": { "InstanceType": "t2.micro" }, "eu-north-1": { "InstanceType": "t3.micro" }, "me-south-1": { "InstanceType": "t3.micro" } } }, "Resources": { "Ec2Instance": { "Type": "AWS::EC2::Instance", "Properties": { "ImageId": { "Ref": "LatestAmiId" }, "InstanceType": { "Fn::FindInMap": [ "RegionMap", { "Ref": "AWS::Region" }, "InstanceType" ] } } } } }
YAML
Parameters: LatestAmiId: Description: The latest Amazon Linux 2 AMI from the Parameter Store Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' Mappings: RegionMap: us-east-1: InstanceType: t2.micro us-west-1: InstanceType: t2.micro eu-west-1: InstanceType: t2.micro eu-north-1: InstanceType: t3.micro me-south-1: InstanceType: t3.micro Resources: Ec2Instance: Type: 'AWS::EC2::Instance' Properties: ImageId: !Ref LatestAmiId InstanceType: !FindInMap - RegionMap - !Ref 'AWS::Region' - InstanceType
In the RegionMap
, each region is mapped to a name-value pair. The name-value
pair is a label, and the value to map. In the RegionMap
,
InstanceType
is the label and the instance type is the value. To use a map to
return a value, you use the Fn::FindInMap function, passing the name of the map, the value used to find the
mapped value, and the label of the mapped value you want to return. In the example above, the
InstanceType
property of the resource Ec2Instance
uses the
Fn::FindInMap
function to determine its value by specifying
RegionMap
as the map to use, AWS::Region
as the input value to map
from, and InstanceType
as the label to identify the value to map to. For example,
if this template were used to create a stack in the US West (N. California) Region,
InstanceType
would be set to t2.micro
.
Constructed values and output values
Parameters and mappings are an excellent way to pass or determine specific values at stack
creation time, but there can be situations where a value from a parameter or other resource
attribute is only part of the value you need. For example, in the following WordPress template
fragment, the Fn::Join
function constructs the Target
subproperty of
the HealthCheck
property for the ElasticLoadBalancer
resource by
concatenating the WebServerPort
parameter with other literal strings to form the
value needed.
JSON
{ "Resources": { "ElasticLoadBalancer": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "AvailabilityZones": { "Fn::GetAZs": "" }, "Instances": [ { "Ref": "Ec2Instance1" }, { "Ref": "Ec2Instance2" } ], "Listeners": [ { "LoadBalancerPort": "80", "InstancePort": { "Ref": "WebServerPort" }, "Protocol": "HTTP" } ], "HealthCheck": { "Target": { "Fn::Join": [ "", [ "HTTP:", { "Ref": "WebServerPort" }, "/" ] ] }, "HealthyThreshold": "3", "UnhealthyThreshold": "5", "Interval": "30", "Timeout": "5" } } } } }
YAML
Resources: ElasticLoadBalancer: Type: 'AWS::ElasticLoadBalancing::LoadBalancer' Properties: AvailabilityZones: !GetAZs '' Instances: - !Ref Ec2Instance1 - !Ref Ec2Instance2 Listeners: - LoadBalancerPort: '80' InstancePort: !Ref WebServerPort Protocol: HTTP HealthCheck: Target: !Join - '' - - 'HTTP:' - !Ref WebServerPort - / HealthyThreshold: '3' UnhealthyThreshold: '5' Interval: '30' Timeout: '5'
The Fn::Join
function takes two parameters, a delimiter that separates the
values you want to concatenate and an array of values in the order that you want them to
appear. In the example above, the Fn::Join
function specifies an empty string as
the delimiter and HTTP:, the value of the WebServerPort
parameter, and a /
character as the values to concatenate. If WebServerPort
had a value of 8888, the
Target
property would be set to the following value:
HTTP:8888/
For more information about the Fn::Join
function, see Fn::Join.
The Fn::Join
function is also useful for declaring output values for the
stack. The Outputs
section in the template contains declarations for the values
that you want to have available after the stack is created. An output is a convenient way to
capture important information about your resources or input parameters. For example, we might
declare the following outputs for a template that creates a WordPress site.
JSON
{ "Outputs": { "InstallURL": { "Value": { "Fn::Join": [ "", [ "http://", { "Fn::GetAtt": [ "ElasticLoadBalancer", "DNSName" ] }, "/wp-admin/install.php" ] ] }, "Description": "Installation URL of the WordPress website" }, "WebsiteURL": { "Value": { "Fn::Join": [ "", [ "http://", { "Fn::GetAtt": [ "ElasticLoadBalancer", "DNSName" ] } ] ] } } } }
YAML
Outputs: InstallURL: Value: !Join - '' - - 'http://' - !GetAtt - ElasticLoadBalancer - DNSName - /wp-admin/install.php Description: Installation URL of the WordPress website WebsiteURL: Value: !Join - '' - - 'http://' - !GetAtt - ElasticLoadBalancer - DNSName
Each output value has a name, a Value
attribute that contains declaration of
the value returned as the output value, and optionally a description of the value. In the
previous example, InstallURL
is the string returned by a Fn::Join
function call that concatenates http://
, the DNS name of the resource
ElasticLoadBalancer
, and /wp-admin/install.php
. The output value
would be similar to the following:
http://mywptests-elasticl-1gb51l6sl8y5v-206169572.
aws-region
.elb.amazonaws.com.cn/wp-admin/install.php
After creating our stack, we might use this link to go to the installation page for the
WordPress blog that we created. CloudFormation generates the output values after it finishes
creating the stack. You can view output values in the Outputs
tab of the
CloudFormation console or by using the describe-stacks CLI command.
Learn more
We just walked through the basic parts of a template and how to use them.
We didn't cover two top level sections in a template:
AWSTemplateFormatVersion
and Description
.
AWSTemplateFormatVersion
is simply the version of the template format. If you
don't specify it, CloudFormation will use the latest version. For more information, see Format version.
The Description
is any valid JSON or YAML string. This description appears in
the Specify Parameters page of the Create Stack
wizard. For more information, see Description.
Of course, there are more advanced template and stack features. Here is a list of a few important ones that you'll want to learn more about:
-
DependsOn — Use this attribute to specify that one resource must be created after another.
-
DeletionPolicy — Use this attribute to specify how CloudFormation should handle the deletion of a resource.
-
Metadata — Use this attribute to specify structured data with a resource.