infra/scripts/state-sync
Viktor Barzin b6faa24349 state: add SOPS-encrypted terraform state to git
- SOPS + age encrypts all 101 .tfstate files (JSON-aware: keys visible, values encrypted)
- scripts/state-sync: encrypt/decrypt/commit wrapper
- scripts/tg: auto-decrypt before ops, auto-encrypt+commit after apply/destroy
- terragrunt.hcl: -backup=- prevents backup file accumulation
- .gitignore: track .tfstate.enc, ignore plaintext .tfstate
- Cleaned 964MB of stale backups (state/backups/, .backup files)
2026-03-17 22:37:56 +00:00

60 lines
1.4 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
STATE_DIR="$REPO_ROOT/state/stacks"
cmd="${1:-help}"
stack="${2:-}" # optional: operate on single stack
encrypt_state() {
local dir="$1"
local src="$dir/terraform.tfstate"
local dst="$dir/terraform.tfstate.enc"
[ -f "$src" ] || return 0
# Only re-encrypt if state is newer than encrypted version
if [ ! -f "$dst" ] || [ "$src" -nt "$dst" ]; then
sops -e --input-type json --output-type json "$src" > "$dst"
fi
}
decrypt_state() {
local dir="$1"
local src="$dir/terraform.tfstate.enc"
local dst="$dir/terraform.tfstate"
[ -f "$src" ] || return 0
sops -d --input-type json --output-type json "$src" > "$dst"
}
case "$cmd" in
encrypt)
if [ -n "$stack" ]; then
encrypt_state "$STATE_DIR/$stack"
else
for dir in "$STATE_DIR"/*/; do
encrypt_state "$dir"
done
fi
;;
decrypt)
if [ -n "$stack" ]; then
decrypt_state "$STATE_DIR/$stack"
else
for dir in "$STATE_DIR"/*/; do
decrypt_state "$dir"
done
fi
;;
commit)
# Encrypt all changed state, then git add + commit
"$0" encrypt
cd "$REPO_ROOT"
git add state/stacks/*/terraform.tfstate.enc
if ! git diff --cached --quiet; then
git commit -m "state: update encrypted terraform state"
fi
;;
help)
echo "Usage: state-sync {encrypt|decrypt|commit} [stack-name]"
;;
esac