Local-only tfstate meant losing the workstation would strand a rebuild (apply would try to recreate the 3 live nodes). Move state to Cloudflare R2, which sits OUTSIDE the Proxmox->VM->cluster->Gitea chain, so a full cluster rebuild can still read it; encrypted at rest via OpenTofu native AES-GCM. Adds a partial s3 backend (R2 skip-flags), gitignored backend.hcl/.r2.env for the account-specific + secret bits, their .example templates, and a migration+DR runbook. Locking (use_lockfile) deferred to an OpenTofu >=1.10 bump (1.9.0 lacks it). Migration (tofu init -migrate-state) runs once the operator provisions the R2 bucket. Co-Authored-By: Claude Opus 4.8 <[email protected]>
25 lines
858 B
Bash
25 lines
858 B
Bash
# Copy to `.r2.env` (gitignored), fill in, then: source .r2.env
|
|
# These are the ONLY secrets. They never enter git or tofu state.
|
|
|
|
# --- R2 S3 credentials (from Cloudflare R2 -> Manage API Tokens -> Object Read & Write) ---
|
|
export AWS_ACCESS_KEY_ID="<R2_ACCESS_KEY_ID>"
|
|
export AWS_SECRET_ACCESS_KEY="<R2_SECRET_ACCESS_KEY>"
|
|
|
|
# --- State-at-rest encryption (OpenTofu native, AES-GCM via PBKDF2 passphrase) ---
|
|
# CRITICAL: store this passphrase in your PASSWORD MANAGER. It is required to read the state on any
|
|
# machine and after any rebuild. It must be >= 16 characters (OpenTofu enforces a minimum).
|
|
export TF_ENCRYPTION='
|
|
key_provider "pbkdf2" "state" {
|
|
passphrase = "<STRONG_PASSPHRASE_MIN_16_CHARS>"
|
|
}
|
|
method "aes_gcm" "state" {
|
|
keys = key_provider.pbkdf2.state
|
|
}
|
|
state {
|
|
method = method.aes_gcm.state
|
|
}
|
|
plan {
|
|
method = method.aes_gcm.state
|
|
}
|
|
'
|