Whether you're setting up a new stack using CloudFormation or trying to decipher an existing stack, understanding CloudFormation syntax is crucial for building, updating, and maintaining AWS resources effectively. In this tutorial, we'll learn by doing. We're going to create two S3 buckets using CloudFormation through the AWS-CLI.
Prerequisites
Before diving into this tutorial, ensure you have the following prerequisites in place:
- AWS CLI installed on your machine.
- AWS credentials configured with the necessary permissions.
Understanding the Process Flow
The flow chart above outlines our process:
- We start by creating an S3 bucket to store our CloudFormation templates.
- Next, we create an aggregated CloudFormation template.
- Finally, we deploy a stack with two nested stacks, each creating an S3 bucket.
Step 1: Create an S3 Bucket and Prepare the Template
First, we'll create an S3 bucket that will store our CloudFormation templates. Execute the following command, replacing and with your unique bucket name and desired AWS region, respectively. Remember, S3 bucket names must be globally unique.
aws s3 mb s3://<your-bucket-name> --region <your-region>
After creating the S3 bucket, set up your project directory with main.json
and S3Template.json
files.
S3Template.json (Nested Stack Template)
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "S3 bucket template", // Description of what this template does
"Parameters": {
"Environment": { "Type": "String" }, // Parameter for environment (e.g., dev, prod)
"ProjectName": { "Type": "String" }, // Parameter for project name
"Application": { "Type": "String" }, // Parameter for application name
"ExpirationInDays": { "Type": "Number" } // Parameter for setting lifecycle expiration in days
},
"Conditions": {
"LifeCycleCondition": { // Condition to check if lifecycle rule is needed
"Fn::Not": [
{ "Fn::Equals": [{ "Ref": "ExpirationInDays" }, 0] }
]
}
},
"Resources": {
"CFS3Bucket": { // Defines an S3 bucket resource
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": { // Bucket name created from a combination of parameters
"Fn::Join": ["-", [{ "Ref": "ProjectName" }, { "Ref": "Environment" }, { "Ref": "Application" }]]
},
"LifecycleConfiguration": { // Sets lifecycle configuration based on the condition
"Fn::If": [
"LifeCycleCondition",
{ "Rules": [{ "ExpirationInDays": { "Ref": "ExpirationInDays" }, "Status": "Enabled" }] },
{ "Ref": "AWS::NoValue" }
]
},
"PublicAccessBlockConfiguration": { // Blocks public access to the bucket
"BlockPublicAcls": "true",
"BlockPublicPolicy": "true",
"IgnorePublicAcls": "true",
"RestrictPublicBuckets": "true"
}
}
}
},
"Outputs": {
"CFS3Bucket": { "Value": { "Ref": "CFS3Bucket" } }, // Outputs the name of the created bucket
"CFS3BucketArn": { "Value": { "Fn::GetAtt": ["CFS3Bucket", "Arn"] } } // Outputs the ARN of the created bucket
}
}
main.json (Main Stack Template)
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "CF template to demonstrate nested stack creation", // Description of what this template does
"Parameters": {
"Environment": { "Type": "String", "Default": "dev" }, // Default parameter for environment
"ProjectName": { "Type": "String", "Default": "gritcoding" } // Default parameter for project name
},
"Resources": {
"S3CatStack": { // Defines a nested stack for 'cat' application
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"Parameters": { // Parameters passed to the nested stack
"ProjectName": { "Ref": "ProjectName" },
"Environment": { "Ref": "Environment" },
"Application": "cat",
"ExpirationInDays": 0
},
"TemplateURL": "S3Template.json" // URL of the template for the nested stack. Initially, this points to the local S3Template.json file.
}
},
"S3DogStack": { // Defines a nested stack for 'dog' application
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"Parameters": { // Parameters passed to the nested stack
"ProjectName": { "Ref": "ProjectName" },
"Environment": { "Ref": "Environment" },
"Application": "dog",
"ExpirationInDays": 0
},
"TemplateURL": "S3Template.json" // URL of the template for the nested stack. Initially, this points to the local S3Template.json file.
}
}
}
}
Important Note on Parameters
When using nested stacks in CloudFormation, it's crucial to ensure that all required parameters in the nested stack (in this case, S3Template.json) are provided by the main stack (main.json). If the main stack doesn't pass these parameters, the CloudFormation deployment will fail.
Step 2: Package the CloudFormation Template
In your project's root directory, package the main.json
and S3Template.json
files into a single template using the following command:
aws --region <your-region> cloudformation package --s3-bucket <your-bucket-name> --template-file ./main.json --output-template-file ./packaged-template.json --use-json
Check your directory for the newly created packaged-template.json
file.
Step 3: Deploy the Packaged Template
Now, deploy the stack to AWS CloudFormation using the command below:
aws cloudformation deploy --template-file ./packaged-template.json --stack-name <your-stack-name>
Visit your AWS console, check the CloudFormation and S3 sections, and you should see the newly created stacks and S3 buckets.
To delete the stack, use:
aws cloudformation delete-stack --stack-name <your stack name>
Confirm the stack's removal in the AWS console.
Learn More
This tutorial aimed to shed light on CloudFormation syntax. For those who prefer hands-on learning, you can fork and explore the source code from this repository: GitHub. And if you found this guide or the repository useful, a star or a reaction would be much appreciated—it's a simple way to show support and keeps me inspired to share more content like this.😄
For further reading and official AWS documentation, refer to:
Top comments (0)