Terraform Pipeline Generator for GitLab CI
Automatically generate pipelines with proper dependency ordering for Terraform/OpenTofu monorepos
Installation • Quick Start • How It Works • Documentation
Managing Terraform in a monorepo is hard:
- Dependencies between modules must be respected (EKS needs VPC first)
- Manual pipelines are tedious to write and maintain
- Full deployments waste time when only one module changed
TerraCi solves this by analyzing your Terraform code and generating optimal GitLab CI pipelines automatically.
brew install edelwud/tap/terracigo install github.com/edelwud/terraci/cmd/terraci@latestdocker run --rm -v $(pwd):/workspace ghcr.io/edelwud/terraci:latest generateDownload from GitHub Releases.
# 1. Initialize configuration
terraci init
# 2. Validate project structure and dependencies
terraci validate
# 3. Generate GitLab CI pipeline
terraci generate -o .gitlab-ci.ymlTerraCi scans your directory structure following the pattern {service}/{environment}/{region}/{module}:
infrastructure/
├── platform/
│ └── prod/
│ └── eu-central-1/
│ ├── vpc/ ← Module: platform/prod/eu-central-1/vpc
│ ├── eks/ ← Module: platform/prod/eu-central-1/eks
│ └── rds/ ← Module: platform/prod/eu-central-1/rds
Dependencies are extracted from terraform_remote_state data sources:
# eks/main.tf
data "terraform_remote_state" "vpc" {
backend = "s3"
config = {
key = "platform/prod/eu-central-1/vpc/terraform.tfstate"
}
}TerraCi understands that eks depends on vpc.
Modules are sorted topologically and grouped into parallel execution levels:
Level 0: vpc (no dependencies)
Level 1: eks, rds (depend on vpc, run in parallel)
Level 2: app (depends on eks)
Generated pipeline:
stages:
- deploy-plan-0
- deploy-apply-0
- deploy-plan-1
- deploy-apply-1
plan-vpc:
stage: deploy-plan-0
apply-vpc:
stage: deploy-apply-0
needs: [plan-vpc]
plan-eks:
stage: deploy-plan-1
needs: [apply-vpc]| Feature | Description |
|---|---|
| Module Discovery | Pattern-based detection at configurable depth (4-5 levels) |
| Dependency Graph | Builds DAG from terraform_remote_state references |
| Topological Sort | Kahn's algorithm ensures correct execution order |
| Parallel Execution | Independent modules run simultaneously |
| Changed-Only Mode | Git diff detection for incremental deployments |
| Policy Checks | OPA-based policy enforcement on Terraform plans |
| MR Integration | Posts plan summaries as GitLab MR comments |
| OpenTofu Support | Single config option to switch from Terraform |
| Visualization | Export dependency graph to DOT/GraphViz format |
| Command | Description |
|---|---|
terraci init |
Create configuration file |
terraci validate |
Validate structure and dependencies |
terraci generate |
Generate GitLab CI pipeline |
terraci graph |
Visualize dependency graph |
terraci summary |
Post plan results to MR (CI only) |
terraci policy pull |
Download policies from configured sources |
terraci policy check |
Check Terraform plans against OPA policies |
# Generate only for changed modules
terraci generate --changed-only --base-ref main -o .gitlab-ci.yml
# Filter by environment
terraci generate --environment prod
# Exclude patterns
terraci generate --exclude "*/sandbox/*" --exclude "*/test/*"
# Auto-approve applies (skip manual trigger)
terraci generate --auto-approve
# Dry run - show what would be generated
terraci generate --dry-runCreate .terraci.yaml in your project root:
structure:
pattern: "{service}/{environment}/{region}/{module}"
min_depth: 4
max_depth: 5
allow_submodules: true
exclude:
- "*/test/*"
- "*/sandbox/*"
gitlab:
image: "hashicorp/terraform:1.6"
plan_enabled: true
auto_approve: false
cache_enabled: true
variables:
TF_IN_AUTOMATION: "true"
job_defaults:
tags:
- terraform
- docker
# MR integration
mr:
comment:
enabled: true
summary_job:
image:
name: "ghcr.io/edelwud/terraci:latest"gitlab:
terraform_binary: "tofu"
image: "ghcr.io/opentofu/opentofu:1.6"TerraCi integrates Open Policy Agent (OPA) to enforce compliance rules:
policy:
enabled: true
sources:
- path: policies # Local policies
- git: https://github.com/org/policies.git
ref: main # Git repository
namespaces:
- terraform
on_failure: block # block, warn, or ignoreExample Rego policy:
package terraform
deny contains msg if {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket"
resource.change.after.acl == "public-read"
msg := sprintf("S3 bucket '%s' must not be public", [resource.name])
}See examples/policy-checks for complete examples.
Full documentation: terraci.dev (or docs/ directory)
Contributions are welcome! Please open an issue or pull request.
MIT