CI/CD Workflow

See how GitHub Actions validates and deploys CloudFormation templates with Rain.


Overview

The starter kit includes GitHub Actions workflows that automatically validate and deploy CloudFormation templates when you push to the main branch. The workflow uses OIDC authentication, runs security scans, and deploys templates with Rain.

Sample workflow

Here's a complete example workflow for deploying to a test environment:

name: Deploy CloudFormation Templates to Test Account

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read
  security-events: write
  actions: read

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

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::${{ vars.TEST_AWS_ACCOUNT_ID }}:role/GitHubActionsServiceRole
          aws-region: ${{ vars.AWS_REGION }}

      - name: Install Rain
        run: |
          RAIN_VERSION=$(curl -s https://api.github.com/repos/aws-cloudformation/rain/releases/latest | jq -r .tag_name)
          curl -L -o rain.zip "https://github.com/aws-cloudformation/rain/releases/download/${RAIN_VERSION}/rain-${RAIN_VERSION}_linux-amd64.zip"
          unzip rain.zip
          chmod +x rain-${RAIN_VERSION}_linux-amd64/rain
          sudo mv rain-${RAIN_VERSION}_linux-amd64/rain /usr/local/bin/
          rm -rf rain-${RAIN_VERSION}_linux-amd64 rain.zip
          rain --version

      - name: Setup Cloud Formation Linter with Latest Version
        uses: scottbrenner/cfn-lint-action@v2

      - name: Run Cloud Formation Linter
        run: cfn-lint

      - name: Checkov GitHub Action
        uses: bridgecrewio/checkov-action@v12
        with:
          config_file: .checkov.yml

      - name: Deploy CloudFormation templates
        run: ./scripts/deploy-templates.sh

Workflow breakdown

Trigger

on:
  push:
    branches: [main]

The workflow triggers automatically on every push to the main branch. This ensures that all changes merged to main are immediately validated and deployed.

Customization options:

  • Add pull request triggers for validation-only runs
  • Add manual workflow dispatch for on-demand deployments
  • Add scheduled triggers for periodic reconciliation

Permissions

permissions:
  id-token: write      # Required for OIDC authentication
  contents: read       # Read repository contents
  security-events: write  # Write security scan results
  actions: read        # Read workflow run information

These permissions enable:

  • id-token: write — Allows the workflow to request an OIDC token for AWS authentication
  • contents: read — Grants access to repository files (templates, scripts, configuration)
  • security-events: write — Enables Checkov to write security findings to GitHub Security tab
  • actions: read — Allows reading workflow run metadata

Job steps

1. Checkout repository

- uses: actions/checkout@v4

Clones the repository so subsequent steps can access templates, scripts, and configuration files.

2. Configure AWS credentials

- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::${{ vars.TEST_AWS_ACCOUNT_ID }}:role/GitHubActionsServiceRole
    aws-region: ${{ vars.AWS_REGION }}

Uses OIDC to assume an IAM role in your AWS account without storing long-lived credentials:

  • role-to-assume — IAM role created by the OIDC provider template
  • TEST_AWS_ACCOUNT_ID — GitHub variable containing your AWS account ID
  • AWS_REGION — GitHub variable for your default region

This step sets AWS credentials in the environment for all subsequent steps.

3. Install Rain

- name: Install Rain
  run: |
    RAIN_VERSION=$(curl -s https://api.github.com/repos/aws-cloudformation/rain/releases/latest | jq -r .tag_name)
    curl -L -o rain.zip "https://github.com/aws-cloudformation/rain/releases/download/${RAIN_VERSION}/rain-${RAIN_VERSION}_linux-amd64.zip"
    unzip rain.zip
    chmod +x rain-${RAIN_VERSION}_linux-amd64/rain
    sudo mv rain-${RAIN_VERSION}_linux-amd64/rain /usr/local/bin/
    rm -rf rain-${RAIN_VERSION}_linux-amd64 rain.zip
    rain --version

Installs the latest version of Rain from GitHub releases:

  1. Fetches the latest release tag from the Rain repository
  2. Downloads the Linux AMD64 binary
  3. Extracts and installs to /usr/local/bin
  4. Verifies installation by printing the version

Rain is used for deploying CloudFormation templates with enhanced features like better error messages and automatic parameter inference.

4. Setup cfn-lint

- name: Setup Cloud Formation Linter with Latest Version
  uses: scottbrenner/cfn-lint-action@v2

Installs cfn-lint, the CloudFormation template validator. This action automatically installs Python and the latest version of cfn-lint.

5. Run cfn-lint

- name: Run Cloud Formation Linter
  run: cfn-lint

Validates all CloudFormation templates against:

  • AWS resource specifications
  • Template syntax and structure
  • Best practices and common errors

Uses the .cfnlintrc configuration file for template selection and rule configuration. The workflow fails if any errors are detected.

For more details, see the cfn-lint reference.

6. Run Checkov

- name: Checkov GitHub Action
  uses: bridgecrewio/checkov-action@v12
  with:
    config_file: .checkov.yml

Scans templates for security misconfigurations and compliance violations:

  • Uses the .checkov.yml configuration file
  • Checks for security best practices (encryption, access controls, logging)
  • Validates compliance frameworks (PCI-DSS, HIPAA, CIS)
  • Reports findings to GitHub Security tab

The workflow fails if critical security issues are detected.

For more details, see the Checkov reference.

7. Deploy templates

- name: Deploy CloudFormation templates
  run: ./scripts/deploy-templates.sh

Deploys all CloudFormation templates using Rain:

  • Iterates through templates in the templates/ directory
  • Matches each template with its corresponding parameter file
  • Deploys stacks with rain deploy --yes
  • Fails the workflow if any deployment fails

For more details, see the Scripts reference.

Validation gates

The workflow implements a fail-fast approach with multiple validation gates:

  1. Template syntax — cfn-lint catches structural errors before deployment
  2. Security compliance — Checkov blocks insecure configurations
  3. Deployment validation — Rain validates templates against AWS APIs
  4. Stack creation — CloudFormation service validates the final deployment

If any gate fails, the workflow stops and no changes reach AWS.

Multi-environment deployments

To deploy to multiple environments (test, staging, production), create separate workflow files:

.github/workflows/
├── deploy-test.yml          # Deploys to TEST_AWS_ACCOUNT_ID
├── deploy-staging.yml       # Deploys to STAGING_AWS_ACCOUNT_ID
└── deploy-production.yml    # Deploys to PRODUCTION_AWS_ACCOUNT_ID

Each workflow uses different:

  • IAM role ARNs (different account IDs)
  • GitHub variables (per-environment account IDs)
  • Environment-specific parameter files

Customizing the pipeline

Selective deployments

To limit deployments to a subset of templates:

# Edit the deploy script to filter templates
./scripts/deploy-templates.sh --filter "network,security"

# Or wrap the script with custom logic

Notifications

Add Slack or Teams notifications after deployment:

- name: Notify on success
  if: success()
  run: |
    curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \
      -H 'Content-Type: application/json' \
      -d '{"text":"CloudFormation deployment succeeded"}'

- name: Notify on failure
  if: failure()
  run: |
    curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \
      -H 'Content-Type: application/json' \
      -d '{"text":"CloudFormation deployment failed"}'

Pull request validation

Add a separate workflow for PR validation (no deployment):

name: Validate CloudFormation Templates

on:
  pull_request:
    branches: [main]

permissions:
  contents: read
  security-events: write

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup cfn-lint
        uses: scottbrenner/cfn-lint-action@v2

      - name: Run cfn-lint
        run: cfn-lint

      - name: Run Checkov
        uses: bridgecrewio/checkov-action@v12
        with:
          config_file: .checkov.yml

This validates templates on every pull request without deploying to AWS.

Observability

Workflow logs

Rain logs stack events directly to the workflow output:

  • View detailed deployment progress
  • See CloudFormation events in real-time
  • Identify which resources are being created/updated/deleted

CloudFormation console

For deeper troubleshooting:

  1. Open the CloudFormation console in your target AWS account
  2. Navigate to the stack matching your template name
  3. Review the Events tab for detailed resource-level information
  4. Check the Resources tab to see the state of all stack resources

GitHub Security tab

Checkov security findings appear in the GitHub Security tab:

  1. Navigate to your repository's Security tab
  2. Click "Code scanning alerts"
  3. Review Checkov findings with severity levels and remediation guidance