CI/CD Workflows

GitHub Actions workflows for validating and deploying CloudFormation templates with Rain.


Overview

The starter kit includes GitHub Actions workflows that validate and deploy CloudFormation templates when you push to main. Workflows use OIDC authentication, run security scans, and deploy with Rain.

Workflow structure

The starter kit includes three workflow files:

WorkflowPurpose
cfn-lint-scan.ymlTemplate syntax and best practices validation
checkov-scan.ymlSecurity and compliance scanning
cloudformation-deploy-<env>.ymlEnvironment-specific deployment

Sample workflow

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

      - name: Deploy templates
        run: ./scripts/deploy-templates.sh -e test

Note: Replace test with your environment name (e.g., staging, production) and update the corresponding GitHub variable (e.g., STAGING_AWS_ACCOUNT_ID).

Job steps explained

1. 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 without storing credentials:

  • TEST_AWS_ACCOUNT_ID - GitHub variable with your account ID
  • AWS_REGION - GitHub variable for your default region

2. Install Rain

Downloads and installs the latest Rain CLI for CloudFormation deployments.

3. Run cfn-lint

Validates templates against AWS resource specifications and best practices. Uses .cfnlintrc for configuration.

4. Run Checkov

Scans templates for security misconfigurations. Uses .checkov.yml for configuration.

5. Deploy templates

Runs ./scripts/deploy-templates.sh to deploy all templates with Rain.

Validation gates

The workflow implements fail-fast validation:

GateDescription
Template syntaxcfn-lint catches structural errors
Security complianceCheckov blocks insecure configurations
Deployment validationRain validates against AWS APIs
Stack creationCloudFormation validates final deployment

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

OIDC authentication

Workflows use OpenID Connect for secure, keyless AWS authentication:

permissions:
  id-token: write      # Request OIDC token
  contents: read       # Read repository files
  security-events: write  # Write Checkov findings

Benefits:

  • No AWS credentials in GitHub Secrets
  • Temporary credentials with automatic expiration
  • Repository-scoped access control
  • Full audit trail via CloudTrail

Multi-environment deployments

Create separate workflow files per environment:

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

Each workflow uses different:

  • IAM role ARNs (different account IDs)
  • GitHub variables
  • Parameter files

Customization

Pull request validation

Add a validation-only workflow for PRs:

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

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

      - run: cfn-lint

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

Notifications

Add Slack notifications:

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

Observability

Workflow logs

Rain logs stack events directly to workflow output:

  • Detailed deployment progress
  • Real-time CloudFormation events
  • Resource create/update/delete visibility

CloudFormation console

For deeper troubleshooting:

  1. Open CloudFormation console in your target account
  2. Navigate to the stack matching your template name
  3. Review Events and Resources tabs

GitHub Security tab

Checkov findings appear under Security → Code scanning alerts.

Next steps