DEV Community

Grit Coding
Grit Coding

Posted on • Updated on

Creating S3 Buckets using CloudFormation via AWS CLI

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

Image description

The flow chart above outlines our process:

  1. We start by creating an S3 bucket to store our CloudFormation templates.
  2. Next, we create an aggregated CloudFormation template.
  3. 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>
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

After creating the S3 bucket, set up your project directory with main.json and S3Template.json files.

Image description

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
    }
}


Enter fullscreen mode Exit fullscreen mode

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.
            }
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Check your directory for the newly created packaged-template.json file.

Image description


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>
Enter fullscreen mode Exit fullscreen mode

Image description

Visit your AWS console, check the CloudFormation and S3 sections, and you should see the newly created stacks and S3 buckets.

Image description

Image description

Image description

To delete the stack, use:

aws cloudformation delete-stack --stack-name <your stack name>
Enter fullscreen mode Exit fullscreen mode

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)