prole/etc/init_kerberos_test.sh
chrisfu bcc8f23a0d Enhance secret management and k8s infrastructure
- Secret Management: Integrated AESGCM for temporary secret handling in install.py and enhanced OpenBao (Vault) support with namespace injection and additional secret paths (Grafana, Kerberos, TDE).
- Infrastructure & K8s:
    - Added Barman Object Store backup configuration (S3) to prole-db.yaml.
    - Updated Prometheus deployment with PVC and persistent configuration.
    - Updated k3s cluster/registry creation scripts.
    - Added etc/build-a-bao.sh for OpenBao setup.
- MSSQL Integration: Updated docker scripts and k8s deployments for Prole MSSQL database.
- Documentation: Added docs/PROLE-CFG-SECRETS.md explaining the new secret handling.
- General: Refined initialization scripts (init_authority.sh, init_openbao.sh, etc.) and updated the ncurses installer.
2026-02-03 22:39:50 -08:00

333 lines
9.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# init_kerberos_test.sh
# Purpose:
# - Run Kerberos authentication checks inside a Kubernetes pod
# - Uses the prole-krb5-conf ConfigMap for krb5.conf
# Initialize SCRIPT_DIR
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
ACTION=${1:-test}
# Load env
if [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/env.sh" ]]; then
set --
# shellcheck disable=SC1090
source "$PROLE_HOME/env.sh"
elif [[ -f "$HOME/.prole/env.sh" ]]; then
set --
# shellcheck disable=SC1090
source "$HOME/.prole/env.sh"
fi
# Load config values from prole.cfg before applying defaults/CLI overrides.
# shellcheck disable=SC1090
source "$SCRIPT_DIR/prole_cfg.sh"
NAMESPACE=${NAMESPACE:-default}
KRB5_REALM=${KRB5_REALM:-${REALM:-}}
KRB5_KDC=${KRB5_KDC:-}
KRB5_USER=${KRB5_USER:-${KRB5_USERNAME:-}}
KRB5_PASSWORD=${KRB5_PASSWORD:-}
KRB5_TEST_IMAGE=${KRB5_TEST_IMAGE:-${PROLE_KRB_TEST_IMAGE:-ubuntu:24.04}}
KRB5_TEST_PACKAGES=${KRB5_TEST_PACKAGES:-"krb5-user krb5-config libpam-krb5 libnss-krb5 adcli samba-common-bin dnsutils ca-certificates"}
REALM_JOIN=${REALM_JOIN:-1}
KEEP_POD=${KEEP_POD:-0}
KRB5_TEST_HOST_NETWORK=${KRB5_TEST_HOST_NETWORK:-0}
KRB5_TEST_DNS_POLICY=${KRB5_TEST_DNS_POLICY:-}
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
}
detect_image() {
if [[ -n "$KRB5_TEST_IMAGE" ]]; then
echo "$KRB5_TEST_IMAGE"
return
fi
echo "ubuntu:24.04"
}
ensure_configmap() {
if kubectl -n "$NAMESPACE" get configmap prole-krb5-conf >/dev/null 2>&1; then
return
fi
echo "ConfigMap prole-krb5-conf not found. Running init_kerberos.sh update..."
if [[ -x "$SCRIPT_DIR/init_kerberos.sh" ]]; then
KRB5_REALM="$KRB5_REALM" KRB5_KDC="$KRB5_KDC" "$SCRIPT_DIR/init_kerberos.sh" update || true
fi
}
create_test_pod() {
local pod_name="$1"
local image="$2"
local host_net_block=""
if [[ "$KRB5_TEST_HOST_NETWORK" == "1" ]]; then
local dns_policy
dns_policy=${KRB5_TEST_DNS_POLICY:-Default}
host_net_block=$' hostNetwork: true\n dnsPolicy: '"$dns_policy"$'\n'
fi
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: ${pod_name}
namespace: ${NAMESPACE}
labels:
app: prole-kerberos-test
spec:
${host_net_block} restartPolicy: Never
containers:
- name: kerberos-test
image: ${image}
command: ["sleep","3600"]
EOF
}
install_kerberos_packages() {
local pod_name="$1"
echo "Installing Kerberos client packages in pod..."
kubectl -n "$NAMESPACE" exec "$pod_name" -- env KRB5_TEST_PACKAGES="$KRB5_TEST_PACKAGES" sh -c '
set -e
if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then
if ! grep -q "universe" /etc/apt/sources.list.d/ubuntu.sources; then
awk "
/^Components:/ {
if (\$0 !~ /universe/) {
\$0 = \$0 \" universe\"
}
}
{ print }
" /etc/apt/sources.list.d/ubuntu.sources > /tmp/ubuntu.sources
mv /tmp/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources
fi
elif [ -f /etc/apt/sources.list ]; then
if ! grep -q "universe" /etc/apt/sources.list; then
sed -i "s/ main$/ main universe/; s/ main restricted$/ main restricted universe/; s/ main restricted multiverse$/ main restricted universe multiverse/" /etc/apt/sources.list
fi
fi
apt-get update
available=""
missing=""
for pkg in $KRB5_TEST_PACKAGES; do
if apt-cache show "$pkg" >/dev/null 2>&1; then
available="$available $pkg"
else
missing="$missing $pkg"
fi
done
if [ -n "$missing" ]; then
echo "WARN: skipping missing packages:$missing" >&2
fi
if [ -z "$available" ]; then
echo "ERROR: none of the requested packages are available." >&2
exit 1
fi
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $available
'
}
resolve_domain() {
local domain="${DOMAIN:-}"
if [[ -z "$domain" ]]; then
domain=$(printf '%s' "$KRB5_REALM" | tr '[:upper:]' '[:lower:]')
fi
printf '%s' "$domain"
}
resolve_host_fqdn() {
local domain="$1"
local host_name="${KRB5_TEST_HOSTNAME:-$2}"
if [[ "$host_name" == *.* ]]; then
printf '%s' "$host_name"
else
printf '%s.%s' "$host_name" "$domain"
fi
}
join_realm() {
local pod_name="$1"
local domain
domain=$(resolve_domain)
local kdc_host
kdc_host=$(printf '%s' "$KRB5_KDC" | awk -F',' '{print $1}' | xargs)
local host_fqdn
host_fqdn=$(resolve_host_fqdn "$domain" "$pod_name")
echo "Registering new Kerberos client as ${host_fqdn} in ${domain} ..."
if kubectl -n "$NAMESPACE" exec "$pod_name" -- sh -c 'command -v adcli >/dev/null 2>&1'; then
printf '%s\n' "$KRB5_PASSWORD" | kubectl -n "$NAMESPACE" exec -i "$pod_name" -- \
adcli join --domain="$domain" --domain-controller "$kdc_host" --login-user "$KRB5_USER" --stdin-password --host-fqdn "$host_fqdn" --show-details
return $?
fi
if kubectl -n "$NAMESPACE" exec "$pod_name" -- sh -c 'command -v realm >/dev/null 2>&1'; then
printf '%s\n' "$KRB5_PASSWORD" | kubectl -n "$NAMESPACE" exec -i "$pod_name" -- \
realm join --user "$KRB5_USER" "$domain"
return $?
fi
echo "ERROR: Neither adcli nor realm found in image; cannot register client." >&2
return 1
}
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
ensure_configmap
local image pod_name
image=$(detect_image)
pod_name="prole-krb-test-$(date +%s)"
echo "Creating Kerberos test pod '$pod_name' in namespace '$NAMESPACE' using image '$image'..."
create_test_pod "$pod_name" "$image"
echo "Waiting for pod to become ready..."
if ! kubectl -n "$NAMESPACE" wait --for=condition=Ready pod/"$pod_name" --timeout=90s; then
echo "Pod did not become ready. Describing pod:"
kubectl -n "$NAMESPACE" describe pod "$pod_name" || true
if [[ "$KEEP_POD" != "1" ]]; then
kubectl -n "$NAMESPACE" delete pod "$pod_name" --ignore-not-found
fi
exit 1
fi
install_kerberos_packages "$pod_name"
echo "Updating /etc/krb5.conf in pod $pod_name from ConfigMap..."
local conf
conf=$(kubectl -n "$NAMESPACE" get configmap prole-krb5-conf -o jsonpath='{.data.krb5\.conf}' 2>/dev/null || true)
if [[ -n "$conf" ]]; then
printf '%s' "$conf" | kubectl -n "$NAMESPACE" exec -i "$pod_name" -- sh -c 'cat > /etc/krb5.conf'
else
echo "WARN: ConfigMap prole-krb5-conf not found; /etc/krb5.conf may be missing or default."
fi
echo "Checking for kinit in pod..."
if ! kubectl -n "$NAMESPACE" exec "$pod_name" -- sh -c 'command -v kinit >/dev/null 2>&1'; then
echo "ERROR: kinit not found after package install in test pod image '$image'." >&2
if [[ "$KEEP_POD" != "1" ]]; then
kubectl -n "$NAMESPACE" delete pod "$pod_name" --ignore-not-found
fi
exit 1
fi
echo "Running kinit for ${KRB5_USER}@${KRB5_REALM} ..."
if ! printf '%s\n' "$KRB5_PASSWORD" | kubectl -n "$NAMESPACE" exec -i "$pod_name" -- kinit "${KRB5_USER}@${KRB5_REALM}"; then
echo "ERROR: kinit failed for ${KRB5_USER}@${KRB5_REALM}." >&2
if [[ "$KEEP_POD" != "1" ]]; then
kubectl -n "$NAMESPACE" delete pod "$pod_name" --ignore-not-found
fi
exit 1
fi
echo "Kerberos ticket cache:"
kubectl -n "$NAMESPACE" exec "$pod_name" -- klist || true
if [[ "${REALM_JOIN:-0}" == "1" ]]; then
if ! join_realm "$pod_name"; then
echo "ERROR: realm join failed." >&2
if [[ "$KEEP_POD" != "1" ]]; then
kubectl -n "$NAMESPACE" delete pod "$pod_name" --ignore-not-found
fi
exit 1
fi
fi
if [[ "$KEEP_POD" != "1" ]]; then
kubectl -n "$NAMESPACE" delete pod "$pod_name" --ignore-not-found
else
echo "KEEP_POD=1 set; leaving test pod running: $pod_name"
fi
}
case "$ACTION" in
test)
run_test
;;
cleanup)
ensure_tools
echo "Deleting kerberos test pods in namespace '$NAMESPACE'..."
kubectl -n "$NAMESPACE" delete pod -l app=prole-kerberos-test --ignore-not-found
;;
*)
echo "Usage: $0 {test|cleanup}" >&2
exit 2
;;
esac