CloudFormation stacks can be deployed from GitHub Actions, but the process often involves a surprising amount of manual configuration for security and state management.

Let’s see a real-world example of deploying a simple S3 bucket using CloudFormation from a GitHub Actions workflow.

Workflow File (.github/workflows/deploy-cfn.yml):

name: Deploy CloudFormation Stack

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:

          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}


          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

          aws-region: us-east-1

      - name: Create or Update CloudFormation Stack
        uses: aws-actions/aws-cloudformation-stack@v1
        with:
          name: my-s3-bucket-stack
          region: us-east-1
          template: ./cloudformation/s3-bucket.yaml
          capabilities: CAPABILITY_IAM
          parameters: |

            BucketName=my-unique-github-action-bucket-${{ github.run_id }}

CloudFormation Template (cloudformation/s3-bucket.yaml):

AWSTemplateFormatVersion: '2010-09-09'
Description: A simple S3 bucket.

Parameters:
  BucketName:
    Type: String
    Description: Name for the S3 bucket.

Resources:
  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

This workflow does the following:

  1. Checks out your repository code. This makes your CloudFormation template available to the workflow.
  2. Configures AWS Credentials. It uses the aws-actions/configure-aws-credentials action to securely inject your AWS access key ID and secret access key (stored as GitHub secrets) into the runner environment. This is crucial for granting your workflow permission to interact with AWS.
  3. Creates or Updates the CloudFormation Stack. The aws-actions/aws-cloudformation-stack action is a wrapper around the AWS CLI’s cloudformation deploy command. It takes the stack name, region, template file, and any necessary capabilities (like CAPABILITY_IAM if your template creates IAM resources) or parameters.

The parameters section dynamically sets the BucketName using the github.run_id to ensure uniqueness for each deployment.

The problem this solves is automating infrastructure provisioning. Instead of manually creating resources in the AWS console or running aws cloudformation deploy locally, you can define your infrastructure as code in a Git repository and have it automatically deployed whenever changes are pushed to a specific branch.

Internally, the aws-actions/aws-cloudformation-stack action orchestrates the aws cloudformation deploy command. This command checks if a stack with the given name already exists. If it does, it performs an update; otherwise, it creates a new stack. It reads your template, resolves parameters, and sends the deployment request to the CloudFormation service. The service then provisions or modifies the resources defined in your template.

The capabilities parameter is essential. If your CloudFormation template creates IAM roles or policies, you must explicitly acknowledge this by including CAPABILITY_IAM or CAPABILITY_NAMED_IAM in your deploy command or action. Without it, CloudFormation will refuse to create or update the stack to prevent accidental creation of powerful IAM permissions.

The parameters section allows you to pass values into your CloudFormation template. These can be hardcoded, or as shown, dynamically generated using GitHub Actions context variables like ${{ github.run_id }} or ${{ github.sha }}. This makes your deployments more flexible and environment-specific.

When you define resources like S3 buckets with PublicAccessBlockConfiguration, you are telling CloudFormation to enforce best practices for security by default. This is part of the "infrastructure as code" paradigm – you define the desired state, and CloudFormation ensures that state is achieved and maintained, including security configurations.

A common point of confusion is how CloudFormation tracks the state of your infrastructure. It doesn’t just execute commands; it maintains a record of the stack’s resources, their states, and any drift from the defined template. This state is managed by AWS’s CloudFormation service itself, not by the GitHub Actions runner. The action simply initiates the process and reports back the outcome.

The next concept you’ll likely encounter is managing drift detection and handling stack failures gracefully within your CI/CD pipeline.

Want structured learning?

Take the full Cloudformation course →