docs(iac): enforce single source of truth for infrastructure

Add IaC practice section to coding-standards.md:
- All infrastructure state via Terraform or Helm (never ad-hoc scripts)
- Clear division: Terraform owns helm releases/namespaces/storage/state
- Anti-pattern: split bucket definitions across multiple files
- Bootstrap-only exception: document one-time setup with rationale

Rationale: prevents state drift, credential duplication, and unclear ownership.
This commit is contained in:
Story Crater Bot
2026-08-18 15:08:01 -07:00
parent 29d5ba3e6e
commit 3a7471fc9b
+53
View File
@@ -70,6 +70,59 @@ set:
--- ---
## Infrastructure as Code (IaC) — Single Source of Truth
**Core principle:** All infrastructure state must be declaratively managed via Terraform or Helm (via helmfile + Terraform). No ad-hoc scripts, manual kubectl, or side-by-side resource definitions.
### Terraform + Helm Division of Labor
- **Terraform manages:**
- Helm releases (chart + version + values)
- Namespaces
- StorageClasses
- Static Kubernetes resources (RBAC, NetworkPolicies, IngressClasses)
- Cloud infrastructure (Vault, S3 backends, secrets)
- State persistence (S3 backend in MinIO)
- **Helmfile manages:**
- Chart release ordering via `needs:`
- Environment-specific value interpolation (Go templating, not shell)
- Hook workflows (pre/post-sync orchestration)
- **Never use helmfile for one-off bucket creation, job runs, or manual setup** — those belong in Terraform or a documented bootstrap process
- **Kubernetes manifests (`k8s/`) manage:**
- ArgoCD applications (single source of truth for GitOps)
- Service definitions that ArgoCD syncs
- **Never manage app objects (Deployments, StatefulSets) directly** — let helm + ArgoCD own them
### Anti-Pattern: Ad-Hoc Resource Creation
❌ **Bad:** Separate `minio-buckets.tf` using `aws_s3_bucket` resources + post-deploy scripts
- Split responsibility: some buckets in Terraform, others in helmfile, others manual
- State drift: unclear what's managed where
- Credential duplication: secrets in multiple places
✅ **Good:** Single source in `minio.tf` helm release:
```hcl
buckets = [
{ name = "terraform-state", policy = "none", purge = false },
{ name = "vault", policy = "none", purge = false },
...
]
```
- One place to define, one place to audit
- Credentials in variables + Vault, not scattered
- TF state tracks all changes
### When to Break the Rule
Only when **explicitly documented**:
- Bootstrap scripts (one-time cluster init) — commit to `scripts/` with clear "run once" warning
- Temporary debugging (never leave in git) — stash or delete before committing
- Manual steps for constraint (e.g., "create namespace before ArgoCD bootstraps") — document in `TROUBLESHOOTING.md` with rationale
---
## YAML & ConfigMap/Secret Patterns ## YAML & ConfigMap/Secret Patterns
### Secret Field Naming ### Secret Field Naming