GitHub Actions IaC CI/CD ArchitectureΒΆ
This CI/CD system is built around modular GitHub Actions & Workflows that are centralized to allow any repository to use them.
- Design Pattern: Automate Terraform Deployments: (1/2) Detect
- Design Pattern: Automate Terraform Deployments: (2/2) Process
- Grinntec GitHub Repo
It provides:
- Automatic detection of changed main.tf files
- Matrix processing for parallel validation of multiple files
- Complete Terraform validation pipeline:
- Format checking, linting, validation
- Planning with cost estimation
- Security scanning with Checkov
- Slack notifications
- Repository context awareness (PROD/DEV/STAGING/DEFAULT)
- Centralized action management with cross-repository compatibility
GitHub StructureΒΆ
Central Organization Wide Repository
This repository hosts the centralized workflows and actions files consumed by the subscription repositories. This means you can modify or change one action file and all the deployments will use that change the next time they run. This is far easier than manually editing the same file multiple times which would be the case if you were to keep the workflows and action files on a per repository basis.
π’
π CENTRALIZED REPOSITORY: grinntec-terraform-deployments-azure/.github
βββ π README.md
βββ π .github/
βββ π actions/ # Reusable Actions Library
β βββ π cache-terraform-providers/ # Cache Terraform providers
β βββ π calculate-file/ # Extract file paths & directories
β βββ π checkov-security-scan/ # Security scanning with Checkov
β βββ π configure-git-private-modules/ # Setup Git for private modules
β βββ π create-terraform-backend-config-file/ # Generate backend config
β βββ π ensure-tf-lockfile-exists/ # Ensure .terraform.lock.hcl exists
β βββ π extract-tfvars/ # Parse .tfvars files
β βββ π read-ci-mode/ # Determine plan/apply/destroy mode
β βββ π slack-notify/ # Send Slack notifications
β βββ π terraform-apply/ # Apply Terraform changes
β βββ π terraform-cost-estimate/ # Cost estimation with Infracost
β βββ π terraform-destroy/ # Destroy Terraform resources
β βββ π terraform-fmt/ # Format Terraform code
β βββ π terraform-plan/ # Plan Terraform changes
β βββ π terraform-validate/ # Validate Terraform syntax
β βββ π tflint/ # Lint Terraform code
β βββ π archive/ # Archived/deprecated actions
βββ π workflows/ # Reusable Workflows
βββ π detect-changed-tfvars-files-multi-repo.yaml # Main orchestrator
βββ π process-changed-main-files.yaml # Matrix processor
Azure Subscription Specific Repository
This is an example of a subscription repository. As the name suggests, it's targeted for a specific Azure subscription and is meant host IaC only for resources within that subscription. Credentials are created per subscription and applied at this level to limit the scope of access the GitHub Actions can perform. To use the centralized repository it requires a single Workflow that when triggered consumes the workflow and action files from the centralized repository.
ποΈ
π SUBSCRIPTION REPOSITORY: grinntec-[environment]-subscription
βββ π README.md
βββ π .gitignore
βββ π .github/
β βββ π workflows/
β βββ π terraform-validation.yaml # Calls centralized workflow
βββ π [app-folder-0]/ # Azure Resource Groups
β βββ π main.tf # Terraform configuration
βββ π [app-folder-1]/
β βββ π main.tf
βββ π [app-folder-2]/
β βββ π main.tf
βββ π [app-folder-x]/
βββ π main.tf
EXAMPLE SUBSCRIPTION REPOSITORIES NAMES:
π grinntec-prod-subscription # π’ Production Environment
π grinntec-dev-subscription # π‘ Development Environment
π grinntec-staging-subscription # π Staging Environment
π grinntec-testing-subscription # π΅ Testing/Sandbox Environment
WORKFLOW EXECUTION FLOW:ΒΆ
- Developer commits to subscription repo (e.g., grinntec-prod-subscription)
terraform-validation.yamltriggers in subscription repo- Calls centralized
detect-changed-tfvars-files-multi-repo.yaml - Detects changed
main.tffiles and repository context - Creates matrix for parallel processing of changed files
- Each matrix job calls
process-changed-main-files.yaml - Executes complete validation pipeline using centralized actions:
βββ π Azure Authentication (OIDC)
βββ π File & Directory Calculation
βββ π― CI Mode Detection (plan/apply/destroy)
βββ π Git Configuration for Private Modules
βββ β‘ Terraform Provider Caching
βββ π§ Backend Configuration Generation
βββ β¨ Terraform Format Check
βββ π§Ή TFLint Analysis
βββ β
Terraform Validation
βββ π Terraform Plan Generation
βββ π‘οΈ Checkov Security Scan
βββ π° Infracost Cost Estimation
βββ π Terraform Apply (if applicable)
βββ π’ Slack Notifications
SECRETS ARCHITECTURE:ΒΆ
Why this split?
- Organization secrets: Same values across all subscription repositories
- Repository secrets: Subscription-specific values that isolate environments
- Security: Each repo can only deploy to its designated subscription
- Maintenance: Update tenant/slack once vs per-repo updates
Security Model
- OIDC Authentication β No static Azure credentials.
- Scoped Secrets β Only required secrets passed to jobs.
- Concurrency Control β Prevents overlapping runs for the same file.
- State Isolation β Backend config ensures environment separation.
π’ ORGANIZATION-LEVEL (shared across all repos):
βββ AZURE_TENANT_ID # Azure AD tenant
βββ AZURE_DEPLOY_TO_MODULE_RO # GitHub token for private modules
βββ INFRACOST_API_KEY # Cost estimation API
βββ SLACK_WEBHOOK_URL # Team notifications
ποΈ REPOSITORY-LEVEL (subscription-specific):
βββ AZURE_CLIENT_ID # Service principal for subscription
βββ AZURE_SUBSCRIPTION_ID # Target Azure subscription
ENVIRONMENT DETECTION:ΒΆ
The centralized workflow automatically determines which Azure environment it's operating in based on the repository name, enabling environment-specific behavior without manual configuration.
Repository Name Pattern β Environment Mapping:
βββ *prod* # PROD
βββ *dev* # DEV
βββ *staging*|*stage* # STAGING
βββ other # DEFAULT
ENVIRONMENT-SPECIFIC SECURITY:
- PROD: Could require additional approvals
- DEV: Allow auto-apply for faster iteration
- STAGING: Require manual approval before apply
- DEFAULT: Safe sandbox mode (plan-only)
DIFFERENTIATED WORKFLOWS:
- PROD: Full security scans + cost alerts
- DEV: Faster validation, skip expensive checks
- STAGING: Production-like validation
- DEFAULT: Basic validation for testing
TARGETED NOTIFICATIONS:
- PROD: Alert leadership + ops team
- DEV: Notify development team only
- STAGING: QA team notifications
- DEFAULT: Individual developer alerts
COST MANAGEMENT:
- PROD: Strict cost thresholds & alerts
- DEV: Relaxed limits for experimentation
- STAGING: Medium cost controls
- DEFAULT: Basic cost awareness