#!/usr/bin/env bash
# scripts/creds-audit.sh -- per-site credential-consolidation audit (SEC-009 enforcement).
#
# Verifies a site's consolidated creds folder (~/<site>-creds/) holds EXACTLY the
# secrets its manifest requires -- each present, non-empty, and with the right mode --
# and that no sensitive file is sprawled loose in the home dir OUTSIDE a *-creds/
# folder. It reads NO secret values: only existence, mode, size, and declared
# provenance (from creds-manifests/<site>.manifest).
#
# WHY THIS EXISTS. SEC-009 established the "ALL site secrets live in ~/<site>-creds/"
# convention, but nothing ENFORCED it, and a secret MINTED ON A SITE VM
# (office1-netbox:/root/netbox-secrets/api.token) was never pulled into the folder --
# it went unnoticed until the fidelity re-check needed it. This audit is the forcing
# check: run it at the END of every site standup and periodically. For the DCs, run
# `creds-audit.sh vr1-dc0` / `vr1-dc1` at standup close so the same gap cannot recur.
#
# Usage:
# bash scripts/creds-audit.sh <site> # e.g. vr1-office1
# Env overrides (used by the harness; not for normal operation):
# CREDS_ROOT parent dir of <site>-creds (default: $HOME)
# MANIFEST_DIR dir holding <site>.manifest (default: <repo>/creds-manifests)
set -uo pipefail
SITE="${1:-}"
[ -n "$SITE" ] || { echo "usage: creds-audit.sh <site> (e.g. vr1-office1)"; exit 2; }
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/.." && pwd)"
CREDS_ROOT="${CREDS_ROOT:-$HOME}"
MANIFEST_DIR="${MANIFEST_DIR:-$REPO/creds-manifests}"
CREDS="$CREDS_ROOT/${SITE}-creds"
MANIFEST="$MANIFEST_DIR/${SITE}.manifest"
F=0
fail() { echo " [FAIL] $1"; F=$((F+1)); }
okln() { echo " [ok] $1"; }
[ -f "$MANIFEST" ] || { echo "FAIL: no manifest at $MANIFEST"; exit 1; }
[ -d "$CREDS" ] || { echo "FAIL: no creds folder at $CREDS"; exit 1; }
echo "=== creds-audit: $SITE ($CREDS) ==="
# 1. folder must be 0700 (owner-only)
fmode=$(stat -c '%a' "$CREDS")
[ "$fmode" = 700 ] && okln "folder mode 0700" || fail "folder mode $fmode (want 0700)"
# 2. every manifest entry present, right mode, non-empty
declare -A expected=()
while read -r fname fmode2 fsrc; do
case "$fname" in ''|\#*) continue;; esac
expected["$fname"]=1
path="$CREDS/$fname"
if [ ! -e "$path" ]; then
fail "MISSING: $fname (provenance: ${fsrc:-?})"
continue
fi
amode=$(stat -c '%a' "$path")
[ "$amode" = "$fmode2" ] || fail "$fname mode $amode (want $fmode2)"
[ -s "$path" ] || fail "$fname is EMPTY"
done < "$MANIFEST"
[ "$F" = 0 ] && okln "all ${#expected[@]} manifest entries present, correct mode, non-empty"
# 3. no UNDECLARED file in the folder (an undeclared secret sitting here is spread)
for path in "$CREDS"/* "$CREDS"/.[!.]*; do
[ -e "$path" ] || continue
b=$(basename "$path")
[ -n "${expected[$b]:-}" ] || fail "UNDECLARED file in folder: $b (add it to the manifest, or remove it)"
done
# 4. sprawl: sensitive-looking files loose in CREDS_ROOT, OUTSIDE any *-creds/ folder
shopt -s nullglob
for path in "$CREDS_ROOT"/*.env "$CREDS_ROOT"/.*.env "$CREDS_ROOT"/*appcred* \
"$CREDS_ROOT"/*-cred*.txt "$CREDS_ROOT"/*authkey* "$CREDS_ROOT"/*.token; do
[ -f "$path" ] || continue
fail "SPRAWL: sensitive file loose in $CREDS_ROOT: $(basename "$path") (belongs in a *-creds/ folder)"
done
shopt -u nullglob
echo
if [ "$F" = 0 ]; then echo "creds-audit $SITE: CLEAN"; exit 0; fi
echo "creds-audit $SITE: $F problem(s) -- consolidate/fix before proceeding"; exit 1