Reconcile render-secrets.sh: sudo-read age key + in-place-write /etc/thermograph.env

The split branch carried the #34-era render-secrets.sh, missing two fixes
required for prod/beta deploy: (1) sudo-read the root-owned 0400 age key into
SOPS_AGE_KEY when the deploy user can't read it directly; (2) in-place-write
/etc/thermograph.env when it's group-writable (beta's non-root 'deploy' user)
instead of only install(1). Without these, deploy.sh's render fails on both
hosts. Flagged by the terraform-layer workstream.
This commit is contained in:
Emi Griffith 2026-07-22 12:56:15 -07:00
parent 75201ef533
commit 86c8e6905c

View file

@ -36,24 +36,40 @@ render_thermograph_secrets() {
fi fi
echo "==> Rendering /etc/thermograph.env from deploy/secrets (common + ${env_name})" echo "==> Rendering /etc/thermograph.env from deploy/secrets (common + ${env_name})"
# The age private key is root-owned (0400). Read it directly if we can, else via
# sudo into SOPS_AGE_KEY — so the key never has to be readable by the deploy user.
# (The render needs sudo to write /etc/thermograph.env below anyway.)
local key_env=()
if [ -r "$key" ]; then
key_env=("SOPS_AGE_KEY_FILE=$key")
else
local keymat; keymat=$(sudo cat "$key" 2>/dev/null | grep '^AGE-SECRET-KEY-' || true)
[ -n "$keymat" ] || { echo "!! cannot read age key at $key (need sudo)" >&2; return 1; }
key_env=("SOPS_AGE_KEY=$keymat")
fi
local tmp; tmp=$(mktemp) local tmp; tmp=$(mktemp)
: > "$tmp" : > "$tmp"
# set -e in the caller makes a decrypt failure fatal here (no partial env). common # set -e in the caller makes a decrypt failure fatal here (no partial env). common
# first, host second, so a host value overrides a shared one (last-wins). # first, host second, so a host value overrides a shared one (last-wins).
if [ -f "$repo/deploy/secrets/common.yaml" ]; then if [ -f "$repo/deploy/secrets/common.yaml" ]; then
SOPS_AGE_KEY_FILE="$key" sops -d --input-type yaml --output-type dotenv \ env "${key_env[@]}" sops -d --input-type yaml --output-type dotenv \
"$repo/deploy/secrets/common.yaml" >> "$tmp" "$repo/deploy/secrets/common.yaml" >> "$tmp"
fi fi
SOPS_AGE_KEY_FILE="$key" sops -d --input-type yaml --output-type dotenv \ env "${key_env[@]}" sops -d --input-type yaml --output-type dotenv \
"$repo/deploy/secrets/${env_name}.yaml" >> "$tmp" "$repo/deploy/secrets/${env_name}.yaml" >> "$tmp"
# /etc/thermograph.env is in the root-owned /etc: write it directly if we can, else # Write /etc/thermograph.env. Prefer an in-place write when the existing file is
# via sudo. Fail loudly rather than deploy against stale secrets. # writable by us (e.g. a group-writable 0660 root:<deploygroup> on a box whose CI
if install -m 0640 "$tmp" /etc/thermograph.env 2>/dev/null; then : # deploy user isn't root and has no broad sudo — beta's `deploy`), since that needs
# only file write, not /etc dir write or sudo. Else install; else sudo install (a
# root/agent deploy). Fail loudly rather than deploy against stale secrets.
if [ -f /etc/thermograph.env ] && [ -w /etc/thermograph.env ]; then
cat "$tmp" > /etc/thermograph.env
elif install -m 0640 "$tmp" /etc/thermograph.env 2>/dev/null; then :
elif sudo install -m 0640 "$tmp" /etc/thermograph.env 2>/dev/null; then : elif sudo install -m 0640 "$tmp" /etc/thermograph.env 2>/dev/null; then :
else else
rm -f "$tmp" rm -f "$tmp"
echo "!! cannot write /etc/thermograph.env (need write access or passwordless sudo)" >&2 echo "!! cannot write /etc/thermograph.env (need file write access or passwordless sudo)" >&2
return 1 return 1
fi fi
rm -f "$tmp" rm -f "$tmp"