#!/usr/bin/env bash set -euo pipefail # init_kerberos_test.sh # Purpose: # - Run Kerberos authentication checks inside the in-cluster KDC pod # Initialize SCRIPT_DIR SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) ORIG_ARGS=("$@") # Load env if [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/env.sh" ]]; then set -- # shellcheck disable=SC1090 source "$PROLE_HOME/env.sh" set -- "${ORIG_ARGS[@]}" elif [[ -f "$HOME/.prole/env.sh" ]]; then set -- # shellcheck disable=SC1090 source "$HOME/.prole/env.sh" set -- "${ORIG_ARGS[@]}" fi # Load config values from prole.cfg before applying defaults/CLI overrides. # shellcheck disable=SC1090 source "$SCRIPT_DIR/prole_cfg.sh" if [[ "${1:-}" == "--mode" || "${1:-}" == "-m" ]]; then prole_set_mode "${2:-}" shift 2 elif [[ "${1:-}" == --mode=* || "${1:-}" == -m=* ]]; then prole_set_mode "${1#*=}" shift fi ACTION=${1:-test} NAMESPACE=${NAMESPACE:-default} SERVICE_NAMESPACE=${SERVICE_NAMESPACE:-${NAMESPACE}} KRB5_REALM=${KRB5_REALM:-${REALM:-}} KRB5_KDC=${KRB5_KDC:-} KRB5_USER=${KRB5_USER:-${KRB5_USERNAME:-}} KRB5_PASSWORD=${KRB5_PASSWORD:-} PROLE_KDC_NAME=${PROLE_KDC_NAME:-dog} PROLE_KDC_SERVICE=${PROLE_KDC_SERVICE:-authority} SAMBA_ADMIN_USER=${SAMBA_ADMIN_USER:-} SAMBA_ADMIN_PASSWORD=${SAMBA_ADMIN_PASSWORD:-} SAMBA_DNS_SERVER=${SAMBA_DNS_SERVER:-} ensure_tools() { for t in kubectl curl jq; do command -v "$t" >/dev/null || { echo "Missing required tool: $t" >&2; exit 1; } done } ensure_namespace() { if ! kubectl get namespace "$NAMESPACE" >/dev/null 2>&1; then echo "Creating namespace '$NAMESPACE' ..." kubectl create namespace "$NAMESPACE" >/dev/null 2>&1 || true fi } openbao_url() { if [[ -n "${PROLE_OPENBAO_URL:-}" ]]; then echo "$PROLE_OPENBAO_URL" elif curl -sS "http://127.0.0.1:18200/v1/sys/health" >/dev/null 2>&1; then echo "http://127.0.0.1:18200" else echo "http://openbao.${NAMESPACE}.svc.cluster.local:8200" fi } openbao_token() { if [[ -f "$PROLE_SERVICE/secrets/openbao-root-token" ]]; then cat "$PROLE_SERVICE/secrets/openbao-root-token" else echo "${OPENBAO_ROOT_TOKEN:-}" fi } fetch_openbao_secret() { local path="$1" local key="$2" local token url token=$(openbao_token) url=$(openbao_url) if [[ -z "$token" ]]; then echo "" return 0 fi curl -sS -H "X-Vault-Token: $token" "$url/v1/kv/data/$path" | jq -r ".data.data.\"$key\"" || echo "" } resolve_krb5_password() { if [[ -z "${KRB5_PASSWORD}" || "${KRB5_PASSWORD}" == '${OPENBAO:'* || "${KRB5_PASSWORD}" == '${PROLE_SECRET:'* ]]; then local path="prole/${NAMESPACE:-default}/kerberos" local fetched fetched=$(fetch_openbao_secret "$path" "password") if [[ -n "$fetched" && "$fetched" != "null" ]]; then KRB5_PASSWORD="$fetched" fi fi } resolve_samba_vars_from_ansible() { if [[ -n "${SAMBA_ADMIN_USER}" && -n "${SAMBA_ADMIN_PASSWORD}" && -n "${SAMBA_DNS_SERVER}" ]]; then return 0 fi local root if [[ -n "${PROLE_HOME:-}" && -d "${PROLE_HOME}" ]]; then root="${PROLE_HOME}" else root="${SCRIPT_DIR}/.." fi local vars_file="${root}/infrastructure/inventory/group_vars/ad_dc/vars.yml" if [[ -f "$vars_file" ]]; then if [[ -z "$SAMBA_DNS_SERVER" ]]; then SAMBA_DNS_SERVER=$(awk -F: '/^[[:space:]]*samba_dns_server[[:space:]]*:/ {sub(/^[^:]+:[[:space:]]*/, "", $0); gsub(/"/, "", $0); print $0; exit}' "$vars_file") fi if [[ -z "$SAMBA_ADMIN_USER" ]]; then SAMBA_ADMIN_USER=$(awk -F: '/^[[:space:]]*samba_dns_admin_user[[:space:]]*:/ {sub(/^[^:]+:[[:space:]]*/, "", $0); gsub(/"/, "", $0); print $0; exit}' "$vars_file") fi fi if [[ -z "$SAMBA_ADMIN_PASSWORD" ]]; then local vault_file="${root}/infrastructure/inventory/group_vars/ad_dc/vault.yml" local vault_pass_file="" if [[ -n "${ANSIBLE_VAULT_PASSWORD_FILE:-}" && -f "${ANSIBLE_VAULT_PASSWORD_FILE}" ]]; then vault_pass_file="${ANSIBLE_VAULT_PASSWORD_FILE}" elif [[ -n "${PROLE_HOME:-}" && -f "${PROLE_HOME}/.vault_pass" ]]; then vault_pass_file="${PROLE_HOME}/.vault_pass" elif [[ -f "${root}/.vault_pass" ]]; then vault_pass_file="${root}/.vault_pass" fi if [[ -f "$vault_file" && -n "$vault_pass_file" && -x "$(command -v ansible-vault)" ]]; then local vault_out vault_out=$(ansible-vault view "$vault_file" --vault-password-file "$vault_pass_file" 2>/dev/null || true) if [[ -n "$vault_out" ]]; then SAMBA_ADMIN_PASSWORD=$(printf '%s\n' "$vault_out" | awk -F: '/^[[:space:]]*vault_samba_dns_admin_pass[[:space:]]*:/ {sub(/^[^:]+:[[:space:]]*/, "", $0); gsub(/"/, "", $0); print $0; exit}') fi fi fi } join_samba_realm_if_needed() { local kdc_ns="$1" local pod_name="$2" local domain="" resolve_samba_vars_from_ansible if [[ -z "$SAMBA_ADMIN_USER" || -z "$SAMBA_ADMIN_PASSWORD" || -z "$SAMBA_DNS_SERVER" ]]; then echo "WARN: Missing Samba join info; skipping samba-tool realm join." return 0 fi if [[ -n "$KRB5_REALM" ]]; then domain=$(printf '%s' "$KRB5_REALM" | tr '[:upper:]' '[:lower:]') fi if [[ -z "$domain" ]]; then domain="$SAMBA_DNS_SERVER" fi if kubectl -n "$kdc_ns" exec "$pod_name" -- test -f /var/lib/samba/private/secrets.tdb >/dev/null 2>&1; then echo "Samba already joined; skipping join." return 0 fi echo "Joining Samba realm '${domain}' (server ${SAMBA_DNS_SERVER}) ..." kubectl -n "$kdc_ns" exec "$pod_name" -- \ env SAMBA_ADMIN_USER="$SAMBA_ADMIN_USER" SAMBA_ADMIN_PASSWORD="$SAMBA_ADMIN_PASSWORD" \ SAMBA_DNS_SERVER="$SAMBA_DNS_SERVER" SAMBA_REALM="${KRB5_REALM:-}" \ /bin/sh -c 'realm_flag=""; [ -n "${SAMBA_REALM}" ] && realm_flag="--realm=${SAMBA_REALM}"; samba-tool domain join "'"$domain"'" MEMBER -U"${SAMBA_ADMIN_USER}%${SAMBA_ADMIN_PASSWORD}" --server="${SAMBA_DNS_SERVER}" ${realm_flag}' || { echo "WARN: samba-tool domain join failed; continuing to Kerberos test." >&2 return 0 } } run_test() { ensure_tools ensure_namespace resolve_krb5_password # Support both names for the toggle from prole.cfg local enabled="${KERBEROS_ENABLED:-${ENABLED:-false}}" if [[ "$enabled" == "false" || "$enabled" == "0" || "$enabled" == "False" ]]; then echo "Kerberos is disabled (KERBEROS_ENABLED=$enabled). Skipping test." return 0 fi if [[ -z "$KRB5_REALM" || -z "$KRB5_USER" || -z "$KRB5_PASSWORD" || -z "$KRB5_KDC" ]]; then echo "ERROR: Missing Kerberos configuration. Ensure KRB5_REALM, KRB5_KDC, KRB5_USER, KRB5_PASSWORD are set." >&2 exit 1 fi if [[ -x "$SCRIPT_DIR/init_kdc.sh" ]]; then SERVICE_NAMESPACE="$SERVICE_NAMESPACE" KRB5_REALM="$KRB5_REALM" KRB5_KDC="$KRB5_KDC" \ KRB5_ADMIN="$KRB5_KDC" KRB5_USER="$KRB5_USER" KRB5_PASSWORD="$KRB5_PASSWORD" \ "$SCRIPT_DIR/init_kdc.sh" update || true fi local kdc_ns pod_name kdc_ns="${SERVICE_NAMESPACE:-${NAMESPACE:-default}}" pod_name=$(kubectl -n "$kdc_ns" get pod -l "app=${PROLE_KDC_NAME}" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) if [[ -z "$pod_name" ]]; then echo "ERROR: KDC pod '${PROLE_KDC_NAME}' not found in namespace '$kdc_ns'. Run init_kdc.sh update first." >&2 exit 1 fi join_samba_realm_if_needed "$kdc_ns" "$pod_name" echo "Running kinit for ${KRB5_USER}@${KRB5_REALM} inside ${PROLE_KDC_NAME} (${pod_name}) ..." if ! printf '%s\n' "$KRB5_PASSWORD" | kubectl -n "$kdc_ns" exec -i "$pod_name" -- \ env KRB5_CONFIG=/opt/prole-kdc/krb5.conf kinit "${KRB5_USER}@${KRB5_REALM}"; then echo "ERROR: kinit failed for ${KRB5_USER}@${KRB5_REALM}." >&2 exit 1 fi echo "Kerberos ticket cache:" kubectl -n "$kdc_ns" exec "$pod_name" -- env KRB5_CONFIG=/opt/prole-kdc/krb5.conf klist || true } case "$ACTION" in test) run_test ;; cleanup) echo "No test pods to cleanup (KDC-based test)." ;; *) echo "Usage: $0 {test|cleanup}" >&2 exit 2 ;; esac