titan-iac/scripts/zot_cred_sync.sh

77 lines
2.4 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Sync Keycloak users into Zot htpasswd.
# Intended to be rendered into a ConfigMap/Job; keep real secrets out of git.
set -euo pipefail
require() { command -v "$1" >/dev/null 2>&1 || { echo "missing required binary: $1" >&2; exit 1; }; }
require curl; require jq; require kubectl; require htpasswd
: "${KEYCLOAK_URL:=https://sso.bstein.dev}"
: "${KEYCLOAK_REALM:=atlas}"
: "${KEYCLOAK_CLIENT_ID:?set KEYCLOAK_CLIENT_ID or export via secret}"
: "${KEYCLOAK_CLIENT_SECRET:?set KEYCLOAK_CLIENT_SECRET or export via secret}"
: "${ZOT_NAMESPACE:=zot}"
: "${HTPASSWD_SECRET_NAME:=zot-htpasswd}"
: "${DEFAULT_PASSWORD:=TempSsoPass!2025}"
: "${UI_PROXY_USER:=zot-ui-proxy}"
: "${UI_PROXY_PASSWORD:=TempSsoUiPass!2025}"
fetch_token() {
curl -fsS -X POST \
-d "grant_type=client_credentials" \
-d "client_id=${KEYCLOAK_CLIENT_ID}" \
-d "client_secret=${KEYCLOAK_CLIENT_SECRET}" \
"${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token" \
| jq -r '.access_token'
}
pull_users() {
local token="$1"
curl -fsS -H "Authorization: Bearer ${token}" \
"${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users?max=500" \
| jq -r '.[] | select(.enabled == true) | select(.username | startswith("service-account-") | not) | .username'
}
decode_secret_file() {
local ns="$1" name="$2" key="$3" out="$4"
if kubectl -n "${ns}" get secret "${name}" >/dev/null 2>&1; then
kubectl -n "${ns}" get secret "${name}" -o "jsonpath={.data.${key}}" | base64 -d > "${out}" || true
else
: > "${out}"
fi
}
ensure_htpasswd_line() {
local user="$1" password="$2" file="$3"
if ! grep -q "^${user}:" "${file}" 2>/dev/null; then
htpasswd -nbB "${user}" "${password}" >> "${file}"
echo "added user ${user} to htpasswd"
fi
}
main() {
local token tmp existing
tmp="$(mktemp)"
existing="$(mktemp)"
trap 'rm -f "${tmp}" "${existing}"' EXIT
decode_secret_file "${ZOT_NAMESPACE}" "${HTPASSWD_SECRET_NAME}" htpasswd "${existing}"
cp "${existing}" "${tmp}"
ensure_htpasswd_line "${UI_PROXY_USER}" "${UI_PROXY_PASSWORD}" "${tmp}"
token="$(fetch_token)"
readarray -t users < <(pull_users "${token}")
for user in "${users[@]}"; do
ensure_htpasswd_line "${user}" "${DEFAULT_PASSWORD}" "${tmp}"
done
kubectl create secret generic "${HTPASSWD_SECRET_NAME}" \
--namespace "${ZOT_NAMESPACE}" \
--from-file=htpasswd="${tmp}" \
--dry-run=client -o yaml | kubectl apply -f -
}
main "$@"