Stage 4 · Provision
Continuous Delivery & GitOps
Environment Promotion Pipelines
Dev-to-prod promotion with immutable artifacts, approvals, and provenance checks — delivering infrastructure changes safely.
Promotion Models
Environment promotion is the process of validated infrastructure changes moving from dev to staging to production. The goal is to test changes in progressively more realistic environments before reaching production.
| Model | How It Works | Best For |
|---|---|---|
| Branch promotion | Dev branch merges to main, main promotes to prod | Simple setups |
| Directory promotion | Changes propagate through environment directories | Terraform with workspaces |
| Image promotion | Container image is promoted through environments | Kubernetes workloads |
| Plan promotion | Same plan artifact is applied to each environment | Strict governance |
Immutable Artifacts
Immutable artifacts ensure the exact same thing that was tested in dev reaches production. Instead of re-running terraform apply with the same code, you apply the same plan artifact. This eliminates configuration drift between environments.
$ terraform plan -out=tfplan
$ terraform show -json tfplan > tfplan.json
$ terraform apply tfplan
# Store the plan artifact
$ cp tfplan artifacts/plan-v1.2.3.bin
$ cp tfplan.json artifacts/plan-v1.2.3.jsonThe plan file is a binary representation of the changes. The JSON file is human-readable. Both are immutable — they represent exactly what was approved. Apply the same file in staging and prod.
- name: Save plan artifact
uses: actions/upload-artifact@v4
with:
name: tfplan-${{ github.sha }}
path: tfplan
retention-days: 30
- name: Download plan for apply
uses: actions/download-artifact@v4
with:
name: tfplan-${{ github.sha }}
path: tfplanThe plan artifact is stored with the commit SHA as identifier. The apply step downloads the same artifact. This ensures the exact approved plan is applied to production.
Approval Workflows
jobs:
apply-dev:
uses: ./.github/workflows/terraform-apply.yml
with:
environment: dev
working_dir: environments/dev
apply-staging:
needs: apply-dev
uses: ./.github/workflows/terraform-apply.yml
with:
environment: staging
working_dir: environments/staging
apply-prod:
needs: apply-staging
uses: ./.github/workflows/terraform-apply.yml
with:
environment: prod
working_dir: environments/prodEach job depends on the previous one. GitHub environment protection rules can require manual approval before the prod job runs. The approval is recorded in the GitHub audit log.
Provenance Checks
- name: Verify plan provenance
run: |
PLAN_SHA=$(sha256sum tfplan | cut -d' ' -f1)
EXPECTED_SHA=$(cat provenance/${{ github.sha }}.sha256)
if [ "$PLAN_SHA" != "$EXPECTED_SHA" ]; then
echo "Plan artifact has been tampered with"
exit 1
fi
echo "Plan artifact verified: $PLAN_SHA"Provenance checks verify that the plan artifact was created by the CI pipeline and has not been tampered with. The SHA256 hash is stored during the plan step and verified during apply.
Pipeline Design
name: Infrastructure Promotion
on:
push:
branches: [main]
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Terraform Plan
run: |
terraform init -backend=false
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
- name: Store plan
uses: actions/upload-artifact@v4
with:
name: tfplan
path: |
tfplan
tfplan.json
policy-check:
needs: plan
runs-on: ubuntu-latest
steps:
- name: Download plan
uses: actions/download-artifact@v4
with:
name: tfplan
- name: OPA check
run: conftest test tfplan.json -p policies/
- name: Cost check
run: infracost breakdown --path tfplan.jsonThe pipeline separates planning from application. The plan step generates the artifact. The policy check validates against policies. Each step is independent and can be parallelized.
Rollback Strategies
- Git revert — revert the commit that introduced the change, let the pipeline redeploy.
- Plan rollback — apply the previous plan artifact that was stored.
- Manual intervention — use terraform state commands to revert specific resources.
- Emergency break-glass — direct access to production with approval.
Keep plan artifacts for at least 30 days. This allows you to rollback to any previous state within that window. Store the JSON alongside the binary for audit purposes.
Even with automated policy checks, production changes should require human approval. Policy checks catch known violations. Humans catch unexpected side effects that policies cannot detect.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.