93 lines
3.2 KiB
Bash
Executable File
93 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Sync Keycloak users into Gitea local accounts (for CLI + tokens).
|
|
# Requires: curl, jq, kubectl. Expects a Keycloak client with realm-management
|
|
# permissions (manage-users) and a Gitea admin token stored in a secret.
|
|
|
|
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
|
|
|
|
: "${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}"
|
|
: "${GITEA_BASE_URL:=https://scm.bstein.dev}"
|
|
: "${GITEA_NAMESPACE:=gitea}"
|
|
: "${GITEA_TOKEN_SECRET_NAME:=gitea-admin-token}"
|
|
: "${GITEA_TOKEN_SECRET_KEY:=token}"
|
|
: "${DEFAULT_PASSWORD:=TempSsoPass!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, (.email // ""), (.firstName // ""), (.lastName // "")] | @tsv'
|
|
}
|
|
|
|
get_gitea_token() {
|
|
if [[ -n "${GITEA_ADMIN_TOKEN:-}" ]]; then
|
|
echo "${GITEA_ADMIN_TOKEN}"
|
|
return
|
|
fi
|
|
kubectl -n "${GITEA_NAMESPACE}" get secret "${GITEA_TOKEN_SECRET_NAME}" -o "jsonpath={.data.${GITEA_TOKEN_SECRET_KEY}}" \
|
|
| base64 -d
|
|
}
|
|
|
|
user_exists() {
|
|
local token="$1" username="$2"
|
|
local code
|
|
code=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
-H "Authorization: token ${token}" \
|
|
"${GITEA_BASE_URL}/api/v1/admin/users/${username}")
|
|
[[ "${code}" == "200" ]]
|
|
}
|
|
|
|
create_user() {
|
|
local token="$1" username="$2" email="$3" fname="$4" lname="$5"
|
|
local body status fullname
|
|
fullname="$(echo "${fname} ${lname}" | xargs)"
|
|
if [[ -z "${email}" ]]; then
|
|
email="${username}@example.local"
|
|
fi
|
|
body=$(jq -n --arg u "${username}" --arg e "${email}" --arg p "${DEFAULT_PASSWORD}" \
|
|
--arg fn "${fullname}" '{username:$u, email:$e, password:$p, must_change_password:false, full_name:$fn}')
|
|
status=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
-H "Authorization: token ${token}" \
|
|
-H "Content-Type: application/json" \
|
|
-X POST \
|
|
-d "${body}" \
|
|
"${GITEA_BASE_URL}/api/v1/admin/users")
|
|
if [[ "${status}" == "201" ]]; then
|
|
echo "created gitea user ${username}"
|
|
elif [[ "${status}" == "409" ]]; then
|
|
echo "gitea user ${username} already exists (409)" >&2
|
|
else
|
|
echo "failed to create gitea user ${username} (status ${status})" >&2
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
local kc_token gitea_token
|
|
kc_token="$(fetch_token)"
|
|
gitea_token="$(get_gitea_token)"
|
|
|
|
while IFS=$'\t' read -r username email fname lname; do
|
|
if user_exists "${gitea_token}" "${username}"; then
|
|
continue
|
|
fi
|
|
create_user "${gitea_token}" "${username}" "${email}" "${fname}" "${lname}"
|
|
done < <(pull_users "${kc_token}")
|
|
}
|
|
|
|
main "$@"
|