name: BUILD | Terraform
TODO: Do not plan on environment that is not changed to prevent lockins.
TODO: Optimize steps (reduce WET code).
TODO: Test execution with multiple environments, modules and change on main, on PR merge and on PR update.
TODO: Add step for cost limit check.
TODO: Add dependency graph generation per environment.
TODO: Add a notification alert to Slack on fail/success.
TODO: Add caching for the .terraform folder between jobs and workflows.
TODO: Optimize checkout steps with a single checkout and shallow clone.
TODO: Add manual workflow for unlocking a specific environment.
TODO: Add condition to stop execution if there are no changes in the PR (verify with testing).
TODO: Split tests from build workflow.
TODO: Integrate SARIF reports where possible.
on: workflow_dispatch: pull_request: branches:
- main types:
- closed
env: GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }} GOOGLE_REGION: ${{ vars.GOOGLE_REGION }} GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }} GITHUB_TOKEN: ${{ secrets.TF_VAR_GITHUB_TOKEN }} GITHUB_OWNER: ${{ secrets.TF_VAR_GITHUB_OWNER }}
jobs: ######################################################################
LINT: Check Terraform formatting and perform additional checks on all environments.
######################################################################
TODO: Add Megalitner.
lint: name: Lint runs-on: self-hosted steps:
-
name: Setup | Repository uses: actions/checkout@v3
-
name: Setup | Terraform uses: hashicorp/setup-terraform@v2 with: terraform_version: 1.6.2
-
name: Lint | Terraform run: terraform fmt -check -diff -recursive ./environments
######################################################################
SCAN: Check repository for leaked secrets.
###################################################################### scan: name: Secrets Scan runs-on: self-hosted steps:
-
name: Setup | Repository uses: actions/checkout@v3
-
name: Scan | Secrets uses: max/secret-scan@master with: exclude_path: ".env.example" continue-on-error: true
######################################################################
SAST: Perform static analysis on Terraform code per environment.
######################################################################
TODO: Make those blocking and add a way to ignore issues.
sast: name: SAST needs:
- lint
- scan
runs-on: self-hosted permissions: contents: read pull-requests: write defaults: run: working-directory: environments/${{ matrix.path }} strategy: fail-fast: false matrix: path:
- dev-01
- dev-01-k8s
- iam
- mgmt-01
- prod-01
- prod-01-k8s steps:
- name: Setup | Repository
uses: actions/checkout@v3
BUG: Fix only one message per PR even when multiple environments are scanned.
-
name: SAST | KICS scan uses: checkmarx/[email protected] with: ignore_on_exit: results enable_comments: true fail_on: medium platform_type: terraform cloud_provider: GCP path: environments/${{ matrix.path }} output_path: myResults/
-
name: SAST | tfsec scan continue-on-error: true uses: aquasecurity/[email protected] with: working_directory: "" github_token: ${{ secrets.GITHUB_TOKEN }}
######################################################################
BUILD: Plan, validate and perform other Terraform procedures per environment.
###################################################################### build: name: Build environment: ${{ matrix.path }} needs:
- lint
- sast
runs-on: self-hosted
strategy:
fail-fast: false
matrix:
path:
- dev-01
- dev-01-k8s
- iam
- mgmt-01
- prod-01
- prod-01-k8s steps:
-
name: Show Region run: | echo ${{ vars.GCP_REGION }}
-
name: Setup | Repository uses: actions/checkout@v3
-
name: Setup | Terraform uses: hashicorp/setup-terraform@v2 with: terraform_version: 1.6.1
-
name: Setup | Secrets uses: oNaiPs/secrets-to-env-action@v1 with: secrets: ${{ toJSON(secrets) }} include: GOOGLE_CREDENTIALS, TF_VAR_INFRACOST_API_KEY, TF_VAR_GITHUB_OWNER, TF_VAR_GITHUB_RUNNER_TOKEN, TF_VAR_GITHUB_TOKEN, TF_VAR_GITHUB_FLUX_TOKEN
-
name: Setup | Helpers id: helpers run: | echo "DATE_NOW=$(date -u +'%T | %m.%d.%Y UTC')" >> "$GITHUB_OUTPUT"
-
name: Terraform | Initialize run: | cd environments/${{ matrix.path }} terraform init -input=false
-
name: Setup | Infracost uses: infracost/actions/setup@v2 with: api-key: ${{ secrets.INFRACOST_API_KEY }}
TODO: Add Infracost result and diff here.
-
name: Terraform | Plan id: plan continue-on-error: true run: | cd environments/${{ matrix.path }} terraform plan -input=false -no-color -out=tfplan \ && terraform show -no-color tfplan
-
name: Terraform | Check Plan Status if: steps.plan.outcome == 'failure' run: | if [ $? != 0 ]; then echo "❌ Terraform plan failed. ❌" fi
-
name: Terraform | Reformat Plan if: steps.plan.outcome == 'success' run: | echo '${{ steps.plan.outputs.stdout || steps.plan.outputs.stderr }}' \ | sed -E 's/^([[:space:]]+)([-+])/\2\1/g' > plan.txt
-
name: Terraform | Plan to ENV if: steps.plan.outcome == 'success' run: | PLAN=$(cat plan.txt) echo "PLAN<<EOF" >> $GITHUB_ENV echo "$PLAN" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV
-
name: Terraform | Comment Plan if: steps.plan.outcome == 'success' uses: mshick/add-pr-comment@v2 with: allow-repeats: true repo-token: ${{ secrets.GITHUB_TOKEN }} message-id: pr-comment-${{ matrix.path }} message: |
Terraform Plan 📝: ${{ matrix.path }}
Generated at: ${{ steps.helpers.outputs.DATE_NOW }} ```diff ${{ env.PLAN }} ```