- GitHub actions workflow to add at `.github/workflows/lib-terraform-plan.yml`
```yaml
---
name: Lib - Terraform Plan
on:
workflow_call:
inputs:
WORKING_DIRECTORY:
required: true
type: string
description: "Working directory"
TF_VERSION:
required: true
type: string
description: "Terraform version"
TF_BACKEND_CONFIG:
required: true
type: string
description: "Terraform backend config"
AWS_REGION:
required: true
type: string
description: "AWS region"
ROLE_TO_ASSUME:
required: true
type: string
description: "ARN of AWS role to assume"
jobs:
terraform-plan:
name: "Terraform Plan"
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: ${{ inputs.WORKING_DIRECTORY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ inputs.TF_VERSION }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ inputs.AWS_REGION }}
role-to-assume: ${{ inputs.ROLE_TO_ASSUME }}
- run: aws sts get-caller-identity
- name: Terraform fmt
id: fmt
run: terraform fmt -check
continue-on-error: true
- name: Terraform Init
id: init
run: terraform init -backend-config=${{ inputs.TF_BACKEND_CONFIG }} -input=false
- name: Terraform Validate
id: validate
run: terraform validate -no-color
- name: Terraform Plan
id: plan
run: terraform plan -input=false -no-color
continue-on-error: true
- name: Terraform Comment
uses: actions/github-script@v7
if: github.event_name == 'pull_request'
env:
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
with:
github-token: ${{ github.token }}
script: |
// 1. Retrieve existing bot comments for the PR
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
})
const botComment = comments.find(comment => {
return comment.user.type === 'Bot' && comment.body.includes('Terraform Format and Style')
})
// 2. Prepare format of the comment
const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
#### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
<details><summary>Validation Output</summary>
\`\`\`\n
${{ steps.validate.outputs.stdout }}
\`\`\`
</details>
#### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`\n
${process.env.PLAN}
\`\`\`
</details>
*Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Working Directory: \`${{ inputs.WORKING_DIRECTORY }}\`, Workflow: \`${{ github.workflow }}\`*`;
// 3. If we have a comment, update it, otherwise create a new one
if (botComment) {
github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: output
})
} else {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
}
```
- GitHub actions workflow to add at `.github/workflows/lib-terraform-apply.yml`
```yaml
---
name: Lib - Terraform Apply
on:
workflow_call:
inputs:
WORKING_DIRECTORY:
required: true
type: string
description: "Working directory"
TF_VERSION:
required: true
type: string
description: "Terraform version"
TF_BACKEND_CONFIG:
required: true
type: string
description: "Terraform backend config"
AWS_REGION:
required: true
type: string
description: "AWS region"
ROLE_TO_ASSUME:
required: true
type: string
description: "ARN of AWS role to assume"
jobs:
terraform-apply:
name: Terraform Apply
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: ${{ inputs.WORKING_DIRECTORY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ inputs.TF_VERSION }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ inputs.AWS_REGION }}
role-to-assume: ${{ inputs.ROLE_TO_ASSUME }}
- run: aws sts get-caller-identity
- name: Terraform Init
id: init
run: terraform init -backend-config=${{ inputs.TF_BACKEND_CONFIG }} -input=false
- name: Terraform Apply
run: terraform apply -input=false -auto-approve
```
- GitHub actions workflow to add at `.github/workflows/lib-validate-tfsec.yml`
```yaml
---
name: Lib - Validate TFSEC
on:
workflow_call:
inputs:
WORKING_DIRECTORY:
required: true
type: string
description: "Working directory"
jobs:
validate_tfsec:
name: Tfsec
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run tfsec
uses: aquasecurity/
[email protected]
with:
working_directory: ${{ inputs.WORKING_DIRECTORY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
```
- GitHub actions workflow to add at `.github/workflows/prod-networking-pr.yml`
```yaml
---
name: Prod Networking PR
on:
pull_request:
branches:
- main
paths:
- 'prod/networking/**'
workflow_dispatch:
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
prod_networking_plan:
uses: .github/workflows/lib-terraform-plan.yml
with:
WORKING_DIRECTORY: "prod/networking"
TF_VERSION: "1.4.2"
TF_BACKEND_CONFIG: "key=prod/networking/terraform.tfstate"
AWS_REGION: "us-west-2"
ROLE_TO_ASSUME: "arn:aws:iam::xxxxxxxxxxxx:role/github"
validate_tfsec:
uses: .github/workflows/lib-validate-tfsec.yml
with:
WORKING_DIRECTORY: "prod/networking"
```
- GitHub actions workflow to add at `.github/workflows/prod-networking.yml`
```yaml
---
name: Prod Networking
on:
push:
branches:
- main
paths:
- 'prod/networking/**'
workflow_dispatch:
permissions:
id-token: write
contents: read
jobs:
prod_networking_apply:
uses: .github/workflows/lib-terraform-apply.yml@main
with:
WORKING_DIRECTORY: "prod/networking"
TF_VERSION: "1.4.2"
TF_BACKEND_CONFIG: "key=prod/networking/terraform.tfstate"
AWS_REGION: "us-west-2"
ROLE_TO_ASSUME: "arn:aws:iam::xxxxxxxxxxxx:role/github"
```
- GitHub actions workflow to add at `.github/workflows/prod-tenants-pr.yml`
```yaml
---
name: Prod tenants PR
on:
pull_request:
branches:
- main
paths:
- '.github/workflows/prod-tenants-pr.yml'
- 'prod/tenants/**'
workflow_dispatch:
env:
paths: 'prod/tenants/*/'
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
get_changed:
runs-on: ubuntu-latest
outputs:
triggering_path: ${{ steps.determine_path.outputs.triggering_path }}
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get changed files
id: changes
run: |
echo "files=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | xargs)" >> $GITHUB_OUTPUT
- name: Determine triggering path
id: determine_path
shell: bash
run: |
# Show paths
echo "Paths: ${{ env.paths }}"
# Get the list of paths being monitored
monitored_paths=$(echo "${{ env.paths }}" | tr "," " ")
echo "Monitored paths: $monitored_paths"
echo "Changed files: ${{ steps.changes.outputs.files }}"
echo "If you see here files that you have not modified, please update your branch with changes from main."
# Loop through each path
for path in $monitored_paths
do
# Check if the modified files include this path
if echo "${{ steps.changes.outputs.files }}" | grep -q "$path"; then
# Set the output variable and exit the loop
echo "triggering_path is $path"
echo "triggering_path=$path" >> $GITHUB_OUTPUT
break
fi
done
- name: Echo changed files
run: echo ${{ steps.determine_path.outputs.triggering_path }}
prod_tenant_plan:
needs: get_changed
uses: .github/workflows/lib-terraform-plan.yml@main
with:
WORKING_DIRECTORY: "${{ needs.get_changed.outputs.triggering_path }}"
TF_VERSION: "1.4.2"
TF_BACKEND_CONFIG: "key=${{ needs.get_changed.outputs.triggering_path }}terraform.tfstate"
AWS_REGION: "us-west-2"
ROLE_TO_ASSUME: "arn:aws:iam::xxxxxxxxxxxx:role/github"
validate_tfsec:
needs: get_changed
uses: .github/workflows/lib-validate-tfsec.yml
with:
WORKING_DIRECTORY: ${{ needs.get_changed.outputs.triggering_path }}
```
- GitHub actions workflow to add at `.github/workflows/prod-tenants.yml`
```yaml
---
name: Prod tenants
on:
pull_request:
branches:
- main
paths:
- '.github/workflows/prod-tenants.yml'
- 'prod/tenants/**'
types: ['labeled']
workflow_dispatch:
env:
paths: 'prod/tenants/*/'
permissions:
id-token: write
contents: read
jobs:
get_changed:
runs-on: ubuntu-latest
outputs:
triggering_path: ${{ steps.determine_path.outputs.triggering_path }}
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get changed files
id: changes
run: |
echo "files=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | xargs)" >> $GITHUB_OUTPUT
- name: Determine triggering path
id: determine_path
shell: bash
run: |
# Show paths
echo "Paths: ${{ env.paths }}"
# Get the list of paths being monitored
monitored_paths=$(echo "${{ env.paths }}" | tr "," " ")
echo "Monitored paths: $monitored_paths"
echo "Changed files: ${{ steps.changes.outputs.files }}"
echo "If you see here files that you have not modified, please update your branch with changes from main."
# Loop through each path
for path in $monitored_paths
do
# Check if the modified files include this path
if echo "${{ steps.changes.outputs.files }}" | grep -q "$path"; then
# Set the output variable and exit the loop
echo "triggering_path is $path"
echo "triggering_path=$path" >> $GITHUB_OUTPUT
break
fi
done
- name: Echo changed files
run: echo ${{ steps.determine_path.outputs.triggering_path }}
prod_tenant_apply:
if: ${{ github.event.label.name == 'tf-apply' }}
needs: get_changed
uses: .github/workflows/lib-terraform-apply.yml
with:
WORKING_DIRECTORY: "${{ needs.get_changed.outputs.triggering_path }}"
TF_VERSION: "1.4.2"
TF_BACKEND_CONFIG: "key=${{ needs.get_changed.outputs.triggering_path }}terraform.tfstate"
AWS_REGION: "us-west-2"
ROLE_TO_ASSUME: "arn:aws:iam::xxxxxxxxxxxx:role/github"
```