Organize local infrastructure and Vault secrets by service ownership
This commit is contained in:
1 parent
1b8800ee73
commit
9dbf0bd80c
44 files changed
+496
-359
No files matched your search
@@ -0,0 +1,63 @@
|
||||
# Shared container-side primitives. Secret JSON travels through stdin or private files.
|
||||
set -eu
|
||||
set -o pipefail
|
||||
umask 077
|
||||
STATE="$PWD/.local/dev"
|
||||
TOOL_STATE=$STATE
|
||||
mkdir -p "$STATE"
|
||||
WORK=$(mktemp -d)
|
||||
cleanup() {
|
||||
rm -rf "$WORK"
|
||||
chown -R "${LOCAL_UID:-0}:${LOCAL_GID:-0}" "$TOOL_STATE"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
trap 'exit 130' INT
|
||||
trap 'exit 143' TERM
|
||||
fail() { echo "$*" >&2; exit 1; }
|
||||
compose() { docker compose --project-directory . -f infra/local/compose.yml --env-file "$STATE/images.env" "$@"; }
|
||||
write() {
|
||||
target=$1; mode=${2:-600}
|
||||
mkdir -p "$(dirname "$target")"
|
||||
cat > "$target.tmp"
|
||||
chmod "$mode" "$target.tmp"
|
||||
mv "$target.tmp" "$target"
|
||||
}
|
||||
# Token is never placed in curl's arguments, errors or response logs.
|
||||
vault() (
|
||||
path=$1; method=${2:-GET}; missing=${3:-no}
|
||||
header=$(mktemp "$WORK/header.XXXXXX")
|
||||
response=$(mktemp "$WORK/response.XXXXXX")
|
||||
trap 'rm -f "$header" "$response"' EXIT
|
||||
printf 'Content-Type: application/json\n' > "$header"
|
||||
if [ -n "${VAULT_TOKEN:-}" ]; then printf 'X-Vault-Token: %s\n' "$VAULT_TOKEN" >> "$header"; fi
|
||||
if [ "$method" = GET ]; then
|
||||
code=$(curl -s --connect-timeout 5 --max-time 30 -H "@$header" -o "$response" -w '%{http_code}' "http://vault:8200/v1/$path") || exit 1
|
||||
else
|
||||
code=$(curl -s --connect-timeout 5 --max-time 30 -H "@$header" -X "$method" --data-binary @- -o "$response" -w '%{http_code}' "http://vault:8200/v1/$path") || exit 1
|
||||
fi
|
||||
case "$code" in
|
||||
200|204) if [ -s "$response" ]; then cat "$response"; else printf '{}'; fi;;
|
||||
404) if [ "$missing" = yes ]; then printf 'null'; else echo "Vault $path returned HTTP $code" >&2; exit 1; fi;;
|
||||
*) echo "Vault $path returned HTTP $code" >&2; exit 1;;
|
||||
esac
|
||||
)
|
||||
existing() {
|
||||
[ -f "$STATE/admin/init.json" ] || fail 'Missing .local/dev/admin/init.json; restore matching bootstrap material'
|
||||
VAULT_TOKEN=$(jq -er '.root_token' "$STATE/admin/init.json")
|
||||
export VAULT_TOKEN
|
||||
}
|
||||
kv() { vault "kv/data/$1" GET yes | jq 'if . == null then null else .data.data end'; }
|
||||
put() { jq '{data:.}' | vault "kv/data/$1" POST >/dev/null; }
|
||||
random() { printf '{"bytes":%s,"format":"hex"}' "${1:-32}" | vault sys/tools/random POST | jq -er '.data.random_bytes'; }
|
||||
ensure() (
|
||||
path=$1
|
||||
value=$(kv "$path")
|
||||
if [ "$value" = null ]; then put "$path"; fi
|
||||
)
|
||||
# Never forward mongosh errors: authentication/command errors may include secrets.
|
||||
mongo() { compose exec -T mongo mongosh --quiet --file /dev/stdin > "$WORK/mongo-result" 2> "$WORK/mongo-error" || return 1; cat "$WORK/mongo-result"; }
|
||||
admin_auth() { kv bootstrap/mongo | jq -r '"const admin=db.getSiblingDB(\"admin\"); admin.auth(\"local-admin\","+(.password|tojson)+");"'; }
|
||||
email_valid() { jq -e '(.api_key|type=="string") and (.api_key|test("\\S")) and (.sender_address|type=="string") and (.sender_address|test("\\S")) and .sender_address!="notifications@localhost.test"' >/dev/null; }
|
||||
export_ca() {
|
||||
compose exec -T frontend cat /data/caddy/pki/authorities/local/root.crt | write "$STATE/ca.pem" 644
|
||||
}
|
||||
Reference in new issue
Block a user