Add Terraform CI/CD pipeline
This commit is contained in:
parent
345f67374c
commit
c057781ad6
248
.gitea/workflows/terraform.yml
Normal file
248
.gitea/workflows/terraform.yml
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
name: Terraform CI/CD Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
action:
|
||||||
|
description: 'Action to perform'
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- plan
|
||||||
|
- apply
|
||||||
|
- destroy
|
||||||
|
|
||||||
|
env:
|
||||||
|
TF_VERSION: "1.9.0"
|
||||||
|
WORKING_DIR: "./terraform" # Adjust to your terraform directory
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Stage 1: Linting and Syntax Checks
|
||||||
|
lint-and-validate:
|
||||||
|
name: Lint and Validate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: https://github.com/hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: ${{ env.TF_VERSION }}
|
||||||
|
|
||||||
|
- name: Terraform Format Check
|
||||||
|
id: fmt
|
||||||
|
run: terraform fmt -check -recursive
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Terraform Init (for validation)
|
||||||
|
run: terraform init -backend=false
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Terraform Validate
|
||||||
|
run: terraform validate
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Check Format Result
|
||||||
|
if: steps.fmt.outcome == 'failure'
|
||||||
|
run: |
|
||||||
|
echo "❌ Terraform formatting check failed. Run 'terraform fmt -recursive' to fix."
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
# Stage 2: Security Scanning
|
||||||
|
security-scan:
|
||||||
|
name: Security Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: lint-and-validate
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run Checkov (Open Source Security Scanner)
|
||||||
|
uses: https://github.com/bridgecrewio/checkov-action@v12
|
||||||
|
with:
|
||||||
|
directory: ${{ env.WORKING_DIR }}
|
||||||
|
framework: terraform
|
||||||
|
soft_fail: false # Set to true to not fail the pipeline on security issues
|
||||||
|
output_format: cli
|
||||||
|
|
||||||
|
- name: Run tfsec (Terraform Security Scanner)
|
||||||
|
uses: https://github.com/aquasecurity/tfsec-action@v1.0.3
|
||||||
|
with:
|
||||||
|
working_directory: ${{ env.WORKING_DIR }}
|
||||||
|
soft_fail: false
|
||||||
|
|
||||||
|
# Stage 3: Terraform Init and Plan
|
||||||
|
plan:
|
||||||
|
name: Terraform Plan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: security-scan
|
||||||
|
if: github.event_name == 'push' || github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && (github.event.inputs.action == 'plan' || github.event.inputs.action == 'apply'))
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: https://github.com/hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: ${{ env.TF_VERSION }}
|
||||||
|
terraform_wrapper: false
|
||||||
|
|
||||||
|
- name: Configure Terraform Credentials
|
||||||
|
run: |
|
||||||
|
# Add your cloud provider credentials here
|
||||||
|
# Example for AWS:
|
||||||
|
# echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> $GITHUB_ENV
|
||||||
|
# echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Example for Azure:
|
||||||
|
# echo "ARM_CLIENT_ID=${{ secrets.ARM_CLIENT_ID }}" >> $GITHUB_ENV
|
||||||
|
# echo "ARM_CLIENT_SECRET=${{ secrets.ARM_CLIENT_SECRET }}" >> $GITHUB_ENV
|
||||||
|
# echo "ARM_SUBSCRIPTION_ID=${{ secrets.ARM_SUBSCRIPTION_ID }}" >> $GITHUB_ENV
|
||||||
|
# echo "ARM_TENANT_ID=${{ secrets.ARM_TENANT_ID }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# For GCP, you might need to create a credentials file
|
||||||
|
echo "Configure your provider credentials here"
|
||||||
|
|
||||||
|
- name: Terraform Init
|
||||||
|
run: terraform init
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
env:
|
||||||
|
# Add backend configuration secrets if needed
|
||||||
|
TF_CLI_ARGS_init: "-backend-config=access_key=${{ secrets.BACKEND_ACCESS_KEY }}"
|
||||||
|
|
||||||
|
- name: Terraform Plan
|
||||||
|
run: terraform plan -out=tfplan.binary
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Convert Plan to JSON
|
||||||
|
run: terraform show -json tfplan.binary > tfplan.json
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Upload Terraform Plan
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: terraform-plan
|
||||||
|
path: |
|
||||||
|
${{ env.WORKING_DIR }}/tfplan.binary
|
||||||
|
${{ env.WORKING_DIR }}/tfplan.json
|
||||||
|
${{ env.WORKING_DIR }}/.terraform/
|
||||||
|
${{ env.WORKING_DIR }}/.terraform.lock.hcl
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
- name: Comment Plan on PR
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const plan = fs.readFileSync('${{ env.WORKING_DIR }}/tfplan.json', 'utf8');
|
||||||
|
const output = `#### Terraform Plan 📖
|
||||||
|
|
||||||
|
<details><summary>Show Plan</summary>
|
||||||
|
|
||||||
|
\`\`\`json
|
||||||
|
${plan}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
</details>`;
|
||||||
|
|
||||||
|
github.rest.issues.createComment({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: output
|
||||||
|
});
|
||||||
|
|
||||||
|
# Stage 4: Terraform Apply
|
||||||
|
apply:
|
||||||
|
name: Terraform Apply
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: plan
|
||||||
|
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'apply')
|
||||||
|
environment:
|
||||||
|
name: production
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: https://github.com/hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: ${{ env.TF_VERSION }}
|
||||||
|
terraform_wrapper: false
|
||||||
|
|
||||||
|
- name: Download Terraform Plan
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: terraform-plan
|
||||||
|
path: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Configure Terraform Credentials
|
||||||
|
run: |
|
||||||
|
# Same credentials configuration as in plan stage
|
||||||
|
echo "Configure your provider credentials here"
|
||||||
|
|
||||||
|
- name: Restore Terraform Init Files
|
||||||
|
run: |
|
||||||
|
# The .terraform directory is already restored from artifacts
|
||||||
|
echo "Terraform initialization files restored"
|
||||||
|
|
||||||
|
- name: Terraform Apply
|
||||||
|
run: terraform apply -auto-approve tfplan.binary
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Output Terraform Outputs
|
||||||
|
run: terraform output -json > terraform-outputs.json
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Upload Terraform Outputs
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: terraform-outputs
|
||||||
|
path: ${{ env.WORKING_DIR }}/terraform-outputs.json
|
||||||
|
retention-days: 90
|
||||||
|
|
||||||
|
# Stage 5: Terraform Destroy (Manual/Authorized Only)
|
||||||
|
destroy:
|
||||||
|
name: Terraform Destroy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'destroy'
|
||||||
|
environment:
|
||||||
|
name: production-destroy # Requires manual approval in repository settings
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: https://github.com/hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: ${{ env.TF_VERSION }}
|
||||||
|
terraform_wrapper: false
|
||||||
|
|
||||||
|
- name: Configure Terraform Credentials
|
||||||
|
run: |
|
||||||
|
# Same credentials configuration as previous stages
|
||||||
|
echo "Configure your provider credentials here"
|
||||||
|
|
||||||
|
- name: Terraform Init
|
||||||
|
run: terraform init
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Terraform Destroy
|
||||||
|
run: terraform destroy -auto-approve
|
||||||
|
working-directory: ${{ env.WORKING_DIR }}
|
||||||
|
|
||||||
|
- name: Notify Destroy Completion
|
||||||
|
run: |
|
||||||
|
echo "🔥 Terraform infrastructure has been destroyed!"
|
||||||
|
echo "Destroyed by: ${{ github.actor }}"
|
||||||
|
echo "Timestamp: $(date -u)"
|
||||||
Loading…
x
Reference in New Issue
Block a user