Keycloak import for realm petrolyst: two clients, petrolyst with MFA for Superset and Traefik, petrolyst-app password only. It lists only app.petrolyst.com and traefik.petrolyst.com, and no customer names, as this repository is public. public.v_operator shows each customer's group. Dashboards overview and site, role Petrolyst Guest, filtered by row. Superset refuses a user with no mapped role. The realm travels with the release: each release's compose files name their realm and secret file, and a rollback needs only its target's secret. Not deployed. Checks earlier on this content: tests/run.sh 109 of 109 and read-only, dashboards import twice, column drift 0, compose config on old and new trees, the secret check on a scratch folder, a rehearsal on a throwaway Keycloak 26.4. Never a real deploy or rollback; shellcheck not installed today, clean when last run. Codex inspected once; its fixes are not re-inspected, on the owner's word. Bands: persistence, Superset. Rules: 1, 2, 3, 6, 14. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
2.8 KiB
Bash
Executable File
78 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Server secrets, run as root after bootstrap.sh.
|
|
# secrets-init.sh generate every missing secret; never overwrites one
|
|
# secrets-init.sh keycloak-secret store the client secret of Keycloak client
|
|
# "petrolyst" of realm "petrolyst"
|
|
# (Clients > petrolyst > Credentials),
|
|
# read from the terminal or stdin
|
|
#
|
|
# Layout: /opt/petrolyst/secrets/{shared,traefik,fuel-monitoring}/ are root:deploy
|
|
# 0750, so only root and the deploy user can reach them; the files are 0444
|
|
# because each container reads them under its own uid.
|
|
set -euo pipefail
|
|
|
|
die() { echo "ERROR: $*" >&2; exit 1; }
|
|
[ "$(id -u)" = 0 ] || die "run as root"
|
|
getent group deploy >/dev/null || die "group deploy is missing: run host/bootstrap.sh first"
|
|
|
|
ROOT=/opt/petrolyst
|
|
SECRETS=$ROOT/secrets
|
|
umask 077
|
|
install -d -o root -g deploy -m 0750 "$SECRETS" "$SECRETS/shared" "$SECRETS/traefik" "$SECRETS/fuel-monitoring"
|
|
|
|
# write_secret <path> <value>: no trailing newline (oauth2-proxy reads the file
|
|
# byte for byte), replaced atomically.
|
|
write_secret() {
|
|
printf '%s' "$2" >"$1.tmp"
|
|
chown root:deploy "$1.tmp"
|
|
chmod 0444 "$1.tmp"
|
|
mv "$1.tmp" "$1"
|
|
}
|
|
|
|
generate() {
|
|
if [ -s "$1" ]; then
|
|
echo "kept $1"
|
|
else
|
|
write_secret "$1" "$(openssl rand -hex "$2")"
|
|
echo "generated $1"
|
|
fi
|
|
}
|
|
|
|
case ${1:-all} in
|
|
keycloak-secret)
|
|
if [ -t 0 ]; then
|
|
printf 'Client secret of Keycloak client "petrolyst": ' >&2
|
|
IFS= read -rs value
|
|
echo >&2
|
|
else
|
|
# `pbpaste | ...` sends no final newline: read then still sets value but
|
|
# fails, which set -e would turn into a silent exit.
|
|
IFS= read -r value || true
|
|
fi
|
|
value=$(printf '%s' "$value" | tr -d '[:space:]')
|
|
[ -n "$value" ] || die "empty secret"
|
|
write_secret "$SECRETS/shared/keycloak_petrolyst_realm_client_secret" "$value"
|
|
echo "stored $SECRETS/shared/keycloak_petrolyst_realm_client_secret"
|
|
exit 0
|
|
;;
|
|
all) ;;
|
|
*) die "usage: secrets-init.sh [keycloak-secret]" ;;
|
|
esac
|
|
|
|
# Hex only, so no value ever needs quoting in a URL or a properties file.
|
|
generate "$SECRETS/fuel-monitoring/superset_secret_key" 32
|
|
generate "$SECRETS/fuel-monitoring/superset_db_password" 32
|
|
generate "$SECRETS/fuel-monitoring/fuel_db_password" 32
|
|
generate "$SECRETS/fuel-monitoring/fuel_db_ro_password" 32
|
|
# 32 hex characters = a 32-byte cookie key, as oauth2-proxy requires.
|
|
generate "$SECRETS/traefik/oauth2_proxy_cookie_secret" 16
|
|
|
|
if [ ! -s "$SECRETS/shared/keycloak_petrolyst_realm_client_secret" ]; then
|
|
echo
|
|
echo "Still missing: the Keycloak client secret. Copy it from Keycloak"
|
|
echo "(realm petrolyst > Clients > petrolyst > Credentials), then run:"
|
|
echo " $0 keycloak-secret"
|
|
exit 1
|
|
fi
|
|
echo "All secrets present."
|