Github Actions — Terraform — CI/CD Multiple Accounts AWS
Tags: devops, aws, githubactions
Published: 2024-06-09 01:02:48

# Terraform - Multiple AWS Accounts

This repository contains a GitHub Actions workflow for managing Terraform deployments across multiple AWS accounts. The workflow allows for planning, manual approval, and applying or destroying Terraform configurations.

## Workflow: Terraform Plan, Approval, and Deploy

### Workflow Dispatch Inputs

- **action**: Specifies the action to perform (`apply` or `destroy`). Default is `apply`.
- **aws_account**: Specifies the AWS account to deploy to (`shared`, `network`, `production`, `stage`, `develop`).
- **terraform_version**: Specifies the version of Terraform to use. Default is `1.8.0`.

### Workflow Jobs

#### 1. Plan

- **Runs on**: `ubuntu-latest`
- **Permissions**: 
  - `actions: read`
  - `issues: write`
  - `id-token: write`
  - `contents: write`
- **Timeout**: 5 minutes
- **Steps**:
  - Checkout the code.
  - Configure AWS credentials based on the selected AWS account.
  - Install and run `tflint` for linting Terraform files.
  - Setup Terraform with the specified version.
  - Initialize Terraform.
  - Plan Terraform changes and save the plan.
  - Cache Terraform files.
  - Upload the Terraform plan as an artifact.

#### 2. Approval

- **Needs**: `plan`
- **Runs on**: `ubuntu-latest`
- **Permissions**: 
  - `actions: read`
  - `issues: write`
  - `id-token: write`
  - `contents: write`
- **Steps**:
  - Request manual approval from the specified approvers.

#### 3. Deploy

- **Needs**: `approval`
- **Runs on**: `ubuntu-latest`
- **Permissions**:
  - `id-token: write`
  - `contents: write`
- **Timeout**: 20 minutes
- **Steps**:
  - Checkout the code.
  - Configure AWS credentials based on the selected AWS account.
  - Setup Terraform with the specified version.
  - Download the Terraform plan artifact.
  - Move the Terraform plan.
  - Initialize Terraform.
  - Apply or destroy the Terraform plan based on the specified action.

## Usage

To trigger the workflow, go to the Actions tab in your GitHub repository, select the `Terraform - Multiple AWS Accounts` workflow, and click on `Run workflow`. Fill in the required inputs and run the workflow.

## Secrets

The following secrets need to be configured in your GitHub repository:

- `AWS_ACCESS_KEY_ID`
- `AWS_SECRET_ACCESS_KEY`
- `AWS_ROLE_ARN_NETWORK`
- `AWS_ROLE_ARN_PROD`
- `AWS_ROLE_ARN_DEVELOP`
- `AWS_ROLE_ARN_STAGE`
- `GITHUB_TOKEN` (automatically provided by GitHub)

## Notes

- Ensure the roles specified in the AWS credentials have the necessary permissions to perform the Terraform actions.
- Modify the role ARNs and other configurations as per your AWS setup.

For more information on GitHub Actions and Terraform, refer to the [GitHub Actions documentation](https://docs.github.com/en/actions) and [Terraform documentation](https://www.terraform.io/docs).

---
Code :  `deploy-to-terraform.yml `

---

```
name: Terraform - Multiple AWS Accounts

on:
  workflow_dispatch:
    inputs:
      action:
        description: 'Action to perform (apply or destroy)'
        required: true
        default: 'apply'
      aws_account:
        description: 'AWS Account to deploy to (shared, network, production, stage, develop)'
        required: true
      terraform_version:
        description: 'Version of Terraform to use'
        required: true
        default: '1.8.0'

jobs:
  plan:
    runs-on: ubuntu-latest
    permissions:
      actions: read
      issues: write
      id-token: write # This is required for requesting the JWT
      contents: write  # This is required for actions/checkout
    timeout-minutes: 5
    steps:
      - name: Checkout Code
        uses: actions/checkout@v2

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'network' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_NETWORK }}
          aws-region: us-east-1

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'prod' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_PROD }}
          aws-region: us-east-1

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'stage' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_STAGE }}
          aws-region: us-east-1

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'develop' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_DEVELOP }}
          aws-region: us-east-1

      - name: Install TFLint
        run: |
          curl -L https://github.com/terraform-linters/tflint/releases/latest/download/tflint_linux_amd64.zip -o tflint.zip
          unzip tflint.zip
          sudo mv tflint /usr/local/bin/
          rm tflint.zip

      - name: Lint Terraform files
        run: tflint

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ github.event.inputs.terraform_version }}
        env:
          AWS_DEFAULT_REGION: us-east-1

      - name: Initialize Terraform
        run: terraform init -reconfigure

      - name: Plan Terraform changes
        run: terraform plan -out=tfplan

      - name: Cache Terraform files
        uses: actions/cache@v2
        with:
          path: |
            .terraform
            .terraform.lock.hcl
          key: ${{ runner.os }}-terraform-${{ hashFiles('**/*.tf') }}
      
      - name: Upload Terraform plan
        uses: actions/upload-artifact@v2
        with:
            name: tfplan
            path: tfplan

  approval:
    needs: plan
    runs-on: ubuntu-latest
    permissions:
      actions: read
      issues: write
      id-token: write # This is required for requesting the JWT
      contents: write  # This is required for actions/checkout
    steps:
      - name: Request Manual Approval
        uses: trstringer/manual-approval@v1
        with:
          secret: ${{ secrets.GITHUB_TOKEN }}
          approvers: alerabello
          minimum-approvals: 1
          additional-approved-words: 'Approve, Approved, approve, approved'
        timeout-minutes: 10

  deploy:
    needs: approval
    runs-on: ubuntu-latest
    permissions:
      id-token: write # This is required for requesting the JWT
      contents: write  # This is required for actions/checkout
    timeout-minutes: 20
    steps:
      - name: Checkout Code
        uses: actions/checkout@v2

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'network' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_NETWORK }}
          aws-region: us-east-1

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'prod' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_PROD }}
          aws-region: us-east-1

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'stage' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_STAGE }}
          aws-region: us-east-1

      - name: Configure AWS Credentials
        if: ${{ github.event.inputs.aws_account == 'develop' }}
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN_DEVELOP }}
          aws-region: us-east-1
      
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ github.event.inputs.terraform_version }}
        
      - name: Download repository artifact
        uses: actions/download-artifact@v2
        with:
          name: tfplan
          path: ./tfplan
      
      - name: Move Terraform plan
        run: mv ./tfplan/tfplan ./tfplan.tfplan
      
      - name: Initialize Terraform
        run: terraform init -reconfigure

      - name: Apply or Destroy Terraform
        run: |
          if [ "${{ github.event.inputs.action }}" == "apply" ]; then
            terraform apply -auto-approve ./tfplan.tfplan
          elif [ "${{ github.event.inputs.action }}" == "destroy" ]; then
            terraform destroy -auto-approve
          else
            echo "Invalid action specified: ${{ github.event.inputs.action }}"
            exit 1
          fi
```