Skip to content

Commit b489112

Browse files
authored
Create reusable workflows for terraform (#5)
* Add reusable terraform validate workflow * Add job name input * Add reusable terraform apply * Move in actions folder * Update apply with vars and env * Use secrets * Update variables * Mask secrets * Add vars to tf plan * Fix typo * Enable terraform apply * Format * Set part version * Fix issue with uses
1 parent 75ece05 commit b489112

4 files changed

Lines changed: 228 additions & 9 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: Lints Markdown files
2222
uses: DavidAnson/markdownlint-cli2-action@v20
2323
with:
24-
globs: '**/*.md'
24+
globs: "**/*.md"
2525
- name: Set up Python ${{ env.python_version }}
2626
uses: actions/setup-python@v5
2727
with:
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
name: Reusable workflow to apply Terraform
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
environment:
7+
description: "GitHub environment"
8+
type: string
9+
required: true
10+
working-directory:
11+
description: "Working directory"
12+
type: string
13+
required: true
14+
tfbackend-project:
15+
description: "Terraform backend project"
16+
type: string
17+
required: true
18+
custom-commands:
19+
description: "Optional shell commands to run before apply"
20+
type: string
21+
required: false
22+
default: ""
23+
terraform-var-flags:
24+
description: 'Extra -var "key=value" flags (space separated)'
25+
type: string
26+
required: false
27+
default: ""
28+
workflow-parts-version:
29+
description: "GitHub workflow parts version (branch/tag/SHA)"
30+
type: string
31+
required: false
32+
default: "main"
33+
secrets:
34+
atlas-publickey:
35+
description: "Atlas public key"
36+
required: true
37+
atlas-privatekey:
38+
description: "Atlas private key"
39+
required: true
40+
atlas-groupid:
41+
description: "Atlas group IP"
42+
required: true
43+
tfbackend-connstring:
44+
description: "Terraform backend connection string"
45+
required: true
46+
tfbackend-dbname:
47+
description: "Terraform backend database name"
48+
required: true
49+
tfbackend-tenant:
50+
description: "Terraform backend tenant"
51+
required: true
52+
tfbackend-username:
53+
description: "Terraform backend user name"
54+
required: true
55+
tfbackend-userpwd:
56+
description: "Terraform backend user password"
57+
required: true
58+
additional-vars:
59+
description: "Additional variables"
60+
required: false
61+
62+
jobs:
63+
deploy:
64+
name: Deploy
65+
runs-on: ubuntu-latest
66+
environment: ${{ inputs.environment }}
67+
defaults:
68+
run:
69+
working-directory: ${{ inputs.working-directory }}
70+
services:
71+
tfbackend:
72+
image: devprofr/terraform-backend-mongodb:latest
73+
env:
74+
Application__IsHttpsRedirectionEnabled: false
75+
ConnectionStrings__MongoDb: ${{ secrets.tfbackend-connstring }}
76+
MongoDb__ConnectionStringName: MongoDb
77+
MongoDb__DatabaseName: ${{ secrets.tfbackend-dbname }}
78+
ports:
79+
- 8080:8080
80+
steps:
81+
- name: Clone repository
82+
uses: actions/checkout@v6
83+
- name: Checkout workflow parts
84+
uses: actions/checkout@v6
85+
with:
86+
repository: devpro/github-workflow-parts
87+
ref: ${{ inputs.workflow-parts-version }}
88+
path: workflow-parts
89+
- name: Add runner ID to MongoDB Atlas
90+
# uses: devpro/github-workflow-parts/actions/mongodb-atlas/add-runner-ip@... cannot be used with an input parameter in it (must be static) so checkout is mandatory
91+
uses: ./workflow-parts/actions/mongodb-atlas/add-runner-ip
92+
with:
93+
atlas-publickey: ${{ secrets.atlas-publickey }}
94+
atlas-privatekey: ${{ secrets.atlas-privatekey }}
95+
atlas-groupid: ${{ secrets.atlas-groupid }}
96+
- name: Set additional variables
97+
run: |
98+
if [[ -z "${{ secrets.additional-vars }}" ]]; then
99+
echo "No additional-vars bundle provided - skipping."
100+
else
101+
echo "${{ secrets.additional-vars }}" | while IFS='=' read -r key val; do
102+
if [[ -n "$val" ]]; then
103+
echo "::add-mask::$val"
104+
fi
105+
done
106+
echo "${{ secrets.additional-vars }}" >> "$GITHUB_ENV"
107+
fi
108+
- name: Run optional custom commands
109+
if: ${{ inputs.custom-commands != '' }}
110+
run: |
111+
${{ inputs.custom-commands }}
112+
- name: Cache Terraform plugins
113+
uses: actions/cache@v5
114+
with:
115+
path: |
116+
~/.terraform.d/plugin-cache
117+
key: terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
118+
- name: Install terraform
119+
uses: hashicorp/setup-terraform@v3
120+
- name: Terraform init
121+
run: terraform init
122+
- name: Terraform validate
123+
run: terraform validate
124+
- name: Terraform plan
125+
run: terraform plan -out=plan.tfplan ${{ inputs.terraform-var-flags }}
126+
- name: Terraform apply
127+
run: terraform apply -auto-approve plan.tfplan ${{ inputs.terraform-var-flags }}
128+
env:
129+
TF_HTTP_ADDRESS: "http://localhost:8080/${{ secrets.tfbackend-tenant }}/state/${{ inputs.tfbackend-project }}"
130+
TF_HTTP_LOCK_ADDRESS: "http://localhost:8080/${{ secrets.tfbackend-tenant }}/state/${{ inputs.tfbackend-project }}/lock"
131+
TF_HTTP_UNLOCK_ADDRESS: "http://localhost:8080/${{ secrets.tfbackend-tenant }}/state/${{ inputs.tfbackend-project }}/lock"
132+
TF_HTTP_USERNAME: "${{ secrets.tfbackend-username }}"
133+
TF_HTTP_PASSWORD: "${{ secrets.tfbackend-userpwd }}"
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: Reusable workflow to validate Terraform project
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
job-name:
7+
description: "Job name"
8+
required: false
9+
type: string
10+
default: "Validate"
11+
working-directory:
12+
description: "Working directory"
13+
required: false
14+
type: string
15+
default: "."
16+
17+
jobs:
18+
terraform-validate:
19+
name: ${{ inputs.job-name }}
20+
runs-on: ubuntu-latest
21+
defaults:
22+
run:
23+
working-directory: ${{ inputs.working-directory }}
24+
steps:
25+
- name: Clone repository
26+
uses: actions/checkout@v6
27+
- name: Cache Terraform plugins
28+
uses: actions/cache@v5
29+
with:
30+
path: |
31+
~/.terraform.d/plugin-cache
32+
key: terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
33+
- name: Install terraform
34+
uses: hashicorp/setup-terraform@v3
35+
- name: Check Terraform format
36+
run: terraform fmt -recursive -check
37+
- name: Terraform Init
38+
run: terraform init -backend=false
39+
- name: Terraform Validate
40+
run: terraform validate
41+
# Checkov is a static code analysis tool for infrastructure as code (IaC) and also a software composition analysis (SCA) tool for images and open source packages (ref. https://github.com/bridgecrewio/checkov)
42+
- name: Run Checkov
43+
uses: bridgecrewio/checkov-action@v12
44+
with:
45+
soft_fail: true
46+
output_format: cli,sarif
47+
output_file_path: console,results.sarif
48+
# quiet: true
49+
# directory: .
50+
# framework: terraform kubernetes helm
51+
# needs GitHub code security > code scanning, not available on private repos
52+
# - name: Upload SARIF file
53+
# uses: github/codeql-action/upload-sarif@v3
54+
# if: success() || failure()
55+
# with:
56+
# sarif_file: results.sarif
57+
- name: Upload SARIF as artifact
58+
uses: actions/upload-artifact@v6
59+
if: always()
60+
with:
61+
name: checkov-sarif-results
62+
path: results.sarif
63+
retention-days: 14
64+
# TFLint is a pluggable terraform linter (ref. https://github.com/terraform-linters/tflint)
65+
- name: Cache TFLint plugins
66+
uses: actions/cache@v5
67+
with:
68+
path: ~/.tflint.d/plugins
69+
key: tflint-${{ hashFiles('**/.tflint.hcl') }}
70+
- name: Setup TFLint
71+
uses: terraform-linters/setup-tflint@v6
72+
with:
73+
tflint_version: v0.60.0 # ref. https://github.com/terraform-linters/tflint/pkgs/container/tflint
74+
- name: Initialize TFLint
75+
run: tflint --init --recursive
76+
env:
77+
GITHUB_TOKEN: ${{ github.token }} # ref. https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md#avoiding-rate-limiting
78+
- name: Run TFLint
79+
run: tflint --recursive --format compact
80+
- name: Run Trivy IaC scan
81+
uses: aquasecurity/trivy-action@0.33.1
82+
with:
83+
scan-type: "config"
84+
format: "sarif"
85+
output: "trivy-results.sarif"
86+
ignore-unfixed: true
87+
severity: "HIGH,CRITICAL"
88+
env:
89+
TF_IN_AUTOMATION: true

mongodb-atlas/add-runner-ip/action.yml renamed to actions/mongodb-atlas/add-runner-ip/action.yml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,15 @@ name: Add GitHub Actions runner public IP to MongoDB Atlas
22
description: Update project IP access list (temporary)
33

44
inputs:
5-
atlas_publickey:
5+
atlas-publickey:
66
description: MongoDB public key
77
required: true
8-
atlas_privatekey:
8+
atlas-privatekey:
99
description: MongoDB private key
1010
required: true
11-
atlas_groupid:
11+
atlas-groupid:
1212
description: MongoDB group ID
1313
required: true
14-
github_runid:
15-
description: GitHub run ID
16-
required: true
1714

1815
runs:
1916
using: "composite"
@@ -36,11 +33,11 @@ runs:
3633
PAYLOAD="[{\"ipAddress\": \"$RUNNER_IP\", \"comment\": \"GH Actions temp - run ${{ github.run_id }}\", \"deleteAfterDate\": \"$DELETE_AFTER\"}]"
3734
3835
# calls Atlas API v2 to add the entry (uses digest Auth via curl)
39-
RESPONSE=$(curl -s -w "%{http_code}" --user "${{inputs.atlas_publickey}}:${{inputs.atlas_privatekey}}" --digest \
36+
RESPONSE=$(curl -s -w "%{http_code}" --user "${{ inputs.atlas-publickey }}:${{ inputs.atlas-privatekey }}" --digest \
4037
-H "Accept: application/vnd.atlas.2023-01-01+json" \
4138
-H "Content-Type: application/json" \
4239
--data "$PAYLOAD" \
43-
"https://cloud.mongodb.com/api/atlas/v2/groups/${{inputs.atlas_groupid}}/accessList")
40+
"https://cloud.mongodb.com/api/atlas/v2/groups/${{ inputs.atlas-groupid }}/accessList")
4441
4542
HTTP_CODE=${RESPONSE: -3}
4643

0 commit comments

Comments
 (0)