Skip to content

Terraform Execution

Policy

Terraform is part of Vayzo CI/CD. Routine staging infrastructure reconciliation is automatic; production infrastructure reconciliation is tied to the release approval gate. Shared/platform changes use an explicit Jenkins ACTION=Infrastructure plan/approval/apply flow.

The knowledge portal build itself never changes infrastructure; Jenkins is the controlled executor.

Safety model

Operation State access Infrastructure change CI behavior
terraform fmt -check No No Every PR/build
terraform init -backend=false + validate No No Every PR/build
terraform plan Yes No Staging release, production release, infrastructure action
saved-plan terraform apply Yes Yes Automatic staging; after approval for production/infrastructure action
terraform destroy Yes Destructive Not part of Jenkins delivery pipeline

Runner

Use scripts/terraform-ci.sh; it executes Terraform in the official hashicorp/terraform:1.9 Docker image.

Credential-free static validation

scripts/terraform-ci.sh validate

This runs:

  1. recursive terraform fmt -check -diff;
  2. terraform init -backend=false;
  3. terraform validate;

for platform, staging, production, and shared.

No R2 state or provider credentials are contacted.

Real plan and apply

A Jenkins Secret-file credential is mounted as TFVARS_FILE. Cloudflare R2 Terraform-state credentials are injected as AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY.

scripts/terraform-ci.sh plan staging
scripts/terraform-ci.sh apply staging

plan writes a binary plan under artifacts/terraform/ plus a text report. apply refuses to run unless that saved plan exists in the current Jenkins workspace. This ensures the applied change is the same change Jenkins planned.

Environment behavior

Staging

Every deploy from release/* and every release tag performs staging plan/apply automatically before Kubernetes Secret synchronization and Helm deployment.

This is intentionally idempotent: a no-change plan simply reconciles to the existing state.

Production

A release tag performs the production plan only after staging has passed. Jenkins archives the plan, presents the single release approval, then applies the saved production plan and continues with Kubernetes deployment.

Platform/shared

These roots can affect more than one application environment or the CI host itself. Use:

ACTION=Infrastructure
INFRA_ENV=platform|shared

Jenkins validates and plans, asks for the infrastructure approval, then applies the saved plan. The same mode is also available for deliberate staging/production infrastructure-only changes.

State backend

State remains in Cloudflare R2 through Terraform's S3-compatible backend. Each root has its own state key. Staging/production read platform state but do not write it.

The R2 state bucket is a bootstrap dependency and remains a one-time setup concern. Its access keys live only in Jenkins Credentials/developer secret stores.

Concurrency

The Jenkinsfile uses disableConcurrentBuilds(), preventing two Vayzo Jenkins executions from applying the same environment simultaneously. Terraform state is not committed to Git.

R2 does not provide DynamoDB-style Terraform state locking, so operators must not run a competing manual terraform apply while Jenkins is reconciling the same root.

Secrets

Do not commit:

*.tfvars
*.tfstate
*.tfstate.*
*.tfplan
.terraform/

Sensitive environment variables are supplied through Jenkins Secret-file credentials or TF_VAR_* variables. Terraform plan artifacts are retained only in the private Jenkins build context required for review/evidence.

Destroy

terraform destroy is deliberately absent from the delivery pipeline. Destruction requires a separate, deliberate recovery/decommissioning procedure with backup confirmation.