AWS CloudFormation best practices
Best practices are recommendations that can help you use AWS CloudFormation more effectively and securely throughout its entire workflow. Learn how to plan and organize your stacks, create templates that describe your resources and the software applications that run on them, and manage your stacks and their resources. The following best practices are based on real-world experience from current CloudFormation customers.
- Planning and organizing
- Creating templates
- Managing stacks
Shorten the feedback loop to improve delivery velocity
Adopt practices and tools that help you shorten the feedback loop for your infrastructure you describe with CloudFormation templates. This includes performing early linting and testing of your templates in your workstation; when you do, you have the opportunity to discover potential syntax and configuration issues even before you submit your contributions to a source code repository. Early discovery of such issues helps with preventing them from reaching formal lifecycle environments, such as development, quality assurance, and production. This early-testing, fail-fast approach gives you the benefits of reducing rework wait time, reducing potential areas of impact, and increasing your level of confidence in having successful provisioning operations.
Tooling choices that help you achieve fail-fast practices include the AWS CloudFormation Lintercfn-lint
) and
TaskCatcfn-lint
tool gives you the ability to validate your CloudFormation templates against the
AWS CloudFormation Resource
Specification. This includes checking valid values for resource properties, as well
as best practices. Plugins for cfn-lint
are available for a number
of code editorscfn-lint
in your source
code repository’s configuration, so that you can perform template validation when you commit
your contributions. For more information, see Git pre-commit validation of AWS CloudFormation templates with cfn-lint
cfn-lint
might have raised—you can use TaskCat to
test your templates by programmatically creating stacks in AWS Regions you choose. TaskCat
also generates a report with a pass/fail grades for each Region you chose.
For a step-by-step, hands-on walkthrough on how to use both tools to shorten the feedback
loop, follow the Linting and Testing lab
Organize your stacks by lifecycle and ownership
Use the lifecycle and ownership of your AWS resources to help you decide what resources should go in each stack. Initially, you might put all your resources in one stack, but as your stack grows in scale and broadens in scope, managing a single stack can be cumbersome and time consuming. By grouping resources with common lifecycles and ownership, owners can make changes to their set of resources by using their own process and schedule without affecting other resources.
For example, imagine a team of developers and engineers who own a website that's hosted on Amazon EC2 Auto Scaling instances behind a load balancer. Because the website has its own lifecycle and is maintained by the website team, you can create a stack for the website and its resources. Now imagine that the website also uses back-end databases, where the databases are in a separate stack that are owned and maintained by database administrators. Whenever the website team or database team needs to update their resources, they can do so without affecting each other's stack. If all resources were in a single stack, coordinating, and communicating updates can be difficult.
For additional guidance about organizing your stacks, you can use two common frameworks: a multi-layered architecture and service-oriented architecture (SOA).
A layered architecture organizes stacks into multiple horizontal layers that build on top of one another, where each layer has a dependency on the layer directly below it. You can have one or more stacks in each layer, but within each layer, your stacks should have AWS resources with similar lifecycles and ownership.
With a service-oriented architecture, you can organize big business problems into manageable parts. Each of these parts is a service that has a clearly defined purpose and represents a self-contained unit of functionality. You can map these services to a stack, where each stack has its own lifecycle and owners. These services (stacks) can be wired together so that they can interact with one another.
Use cross-stack references to export shared resources
When you organize your AWS resources based on lifecycle and ownership, you might want to
build a stack that uses resources that are in another stack. You can hardcode values or use
input parameters to pass resource names and IDs. However, these methods can make templates
difficult to reuse or can increase the overhead to get a stack running. Instead, use
cross-stack references to export resources from a stack so that other stacks can use them.
Stacks can use the exported resources by calling them using the Fn::ImportValue
function.
For example, you might have a network stack that includes a VPC, a security group, and a subnet. You want all public web applications to use these resources. By exporting the resources, you allow all stacks with public web applications to use them. For more information, see Get exported outputs from a deployed CloudFormation stack.
Verify quotas for all resource types
Before launching a stack, ensure that you can create all the resources that you want without hitting your AWS account limits. If you hit a limit, CloudFormation won't create your stack successfully until you increase your quota or delete extra resources. Each service can have various limits that you should be aware of before launching a stack. For example, by default, you can only launch 2000 CloudFormation stacks per Region in your AWS account. For more information about limits and how to increase the default limits, see AWS service quotas in the AWS General Reference.
Reuse templates to replicate stacks in multiple environments
After you have your stacks and resources set up, you can reuse your templates to replicate your infrastructure in multiple environments. For example, you can create environments for development, testing, and production so that you can test changes before implementing them into production. To make templates reusable, use the parameters, mappings, and conditions sections so that you can customize your stacks when you create them. For example, for your development environments, you can specify a lower-cost instance type compared to your production environment, but all other configurations and settings remain the same. For more information about parameters, mappings, and conditions, see CloudFormation template sections.
Use modules to reuse resource configurations
As your infrastructure grows, common patterns can emerge in which you declare the same components in each of your templates. Modules are a way for you to package resource configurations for inclusion across stack templates, in a transparent, manageable, and repeatable way. Modules can encapsulate common service configurations and best practices as modular, customizable building blocks for you to include in your stack templates.
These building blocks can be for a single resource, like best practices for defining an Amazon Elastic Compute Cloud (Amazon EC2) instance, or they can be for multiple resources, to define common patterns of application architecture. These building blocks can be nested into other modules, so you can stack your best practices into higher-level building blocks. CloudFormation modules are available in the CloudFormation registry, so you can use them just like a native resource. When you use a CloudFormation module, the module template is expanded into the consuming template, which makes it possible for you to access the resources inside the module using a Ref or Fn::GetAtt. For more information, see Create reusable resource configurations that can be included across templates with CloudFormation modules.
Use AWS-specific parameter types
If your template requires inputs for existing AWS-specific values, such as existing
Amazon Virtual Private Cloud IDs or an Amazon EC2 key pair name, use AWS-specific parameter types. For example, you
can specify a parameter as type AWS::EC2::KeyPair::KeyName
, which takes an
existing key pair name that's in your AWS account and in the Region where you are creating
the stack. AWS CloudFormation can quickly validate values for AWS-specific parameter types before
creating your stack. Also, if you use the CloudFormation console, CloudFormation shows a drop down
list of valid values, so you don't have to look up or memorize the correct VPC IDs or key pair
names. For more information, see Reference existing resources and
Systems Manager parameters with CloudFormation-supplied parameter types.
Use parameter constraints
With constraints, you can describe allowed input values so that CloudFormation catches any not valid values before creating a stack. You can set constraints such as a minimum length, maximum length, and allowed patterns. For example, you can set constraints on a database user name value so that it must be a minimum length of eight character and contain only alphanumeric characters. For more information, see Parameters section syntax reference for CloudFormation templates.
Use pseudo parameters to promote portability
You can use pseudo
parameters in your templates as arguments for intrinsic
functions, such as Ref
and Fn::Sub
. Pseudo parameters are
parameters that are predefined by CloudFormation. You don't declare them in your template. Using
pseudo parameters in intrinsic functions increases the portability of your stack templates
across Regions and accounts.
For example, imagine you wanted to create a template where, for a given resource property,
you need to specify the Amazon Resource Name (ARN) of
another existing resource. In this case, the existing resource is an AWS Systems Manager
Parameter Store resource with the following ARN:
arn:aws:ssm:us-east-1:123456789012:parameter/MySampleParameter
. You will need
to adapt the ARN format to your
target AWS partition, Region, and account ID. Instead of hard-coding these values, you can
use AWS::Partition
, AWS::Region
, and AWS::AccountId
pseudo parameters to make your template more portable. In this case, the following example
shows you how to concatenate elements in an ARN with CloudFormation: !Sub
'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/MySampleParameter
.
For another example, assume you want to share resources or configurations across multiple
stacks. In this example, assume you have created a subnet for your VPC, and then
exported its ID for use with other stacks in the same AWS account and Region. In another
stack, you reference the exported value of the subnet ID when describing an Amazon EC2 instance.
For a detailed example of using the Export
output field and
Fn::ImportValue
intrinsic function, see Refer to resource outputs in another CloudFormation
stack.
Stack exports must be unique per account and Region. So, in this case, you can use the
AWS::StackName
pseudo parameter to create a prefix for your export. Since stack
names must also be unique per account and Region, the usage of this pseudo parameter as a
prefix increases the possibility of having a unique export name while also promoting a
reusable approach across stacks from where you export values. Alternatively, you can use a
prefix of your own choice.
Use AWS::CloudFormation::Init
to deploy software
applications on Amazon EC2 instances
When you launch stacks, you can install and configure software applications on Amazon EC2
instances by using the cfn-init
helper script and the AWS::CloudFormation::Init
resource. By using AWS::CloudFormation::Init
, you can describe the configurations
that you want rather than scripting procedural steps. You can also update configurations
without recreating instances. And if anything goes wrong with your configuration, CloudFormation
generates logs that you can use to investigate issues.
In your template, specify installation and configuration states in the
AWS::CloudFormation::Init
resource. For a walkthrough that shows how to use
cfn-init
and AWS::CloudFormation::Init
, see Deploy applications on Amazon EC2.
Use the latest helper scripts
The helper scripts are updated
periodically. Be sure you include the following command in the UserData
property
of your template before you call the helper scripts to ensure that your launched instances get
the latest helper scripts:
yum install -y aws-cfn-bootstrap
For more information about getting the latest helper scripts, see the CloudFormation helper scripts reference.
Validate templates before using them
Before you use a template to create or update a stack, you can use CloudFormation to validate it. Validating a template can help you catch syntax and some semantic errors, such as circular dependencies, before CloudFormation creates any resources. If you use the CloudFormation console, the console automatically validates the template after you specify input parameters. For the AWS CLI or CloudFormation API, use the validate-template CLI command or ValidateTemplate API operation.
During validation, CloudFormation first checks if the template is valid JSON. If it isn't, CloudFormation checks if the template is valid YAML. If both checks fail, CloudFormation returns a template validation error.
Validate templates for organization policy compliance
You can also validate your template for compliance to organization policy guidelines.
AWS CloudFormation Guard (cfn-guard
) is an open-source command line interface (CLI) tool
that provides a policy-as-code language to define rules that can check for both required and
prohibited resource configurations. It then enables you to validate your templates against
those rules. For example, administrators can create rules to ensure that users always create
encrypted Amazon S3 buckets.
You can use cfn-guard
either locally, while editing templates, or
automatically as part of a CI/CD pipeline to stop deployment of non-compliant
resources.
Additionally, cfn-guard
includes a feature, rulegen
, that
enables you to extract rules from existing compliant CloudFormation templates.
For more information, see the cfn-guard
Manage all stack resources through AWS CloudFormation
After you launch a stack, use the CloudFormation console
For more information on drift, see What is drift?.
For more information on updating stacks, see Walkthrough: Updating a stack.
Create change sets before updating your stacks
Change sets allow you to see how proposed changes to a stack might impact your running resources before you implement them. CloudFormation doesn't make any changes to your stack until you run the change set, allowing you to decide whether to proceed with your proposed changes or create another change set.
Use change sets to check how your changes might impact your running resources, especially for critical resources. For example, if you change the name of an Amazon RDS database instance, CloudFormation will create a new database and delete the old one; you will lose the data in the old database unless you've already backed it up. If you generate a change set, you will see that your change will replace your database. This can help you plan before you update your stack. For more information, see Update CloudFormation stacks using change sets.
Use stack policies
Stack policies help protect critical stack resources from unintentional updates that could cause resources to be interrupted or even replaced. A stack policy is a JSON document that describes what update actions can be performed on designated resources. Specify a stack policy whenever you create a stack that has critical resources.
During a stack update, you must explicitly specify the protected resources that you want to update; otherwise, no changes are made to protected resources. For more information, see Prevent updates to stack resources.
Use code reviews and revision controls to manage your templates
Your stack templates describe the configuration of your AWS resources, such as their property values. To review changes and to keep an exact history of your resources, use code reviews and revision controls. These methods can help you track changes between different versions of your templates, which can help you track changes to your stack resources. Also, by maintaining a history, you can always revert your stack to a certain version of your template.
Update your Amazon EC2 instances regularly
On all your Amazon EC2 Windows instances and Amazon EC2 Linux instances created with CloudFormation,
regularly run the yum update
command to update the RPM package. This ensures that
you get the latest fixes and security updates.