prole/etc/init_kdc.sh
chrisfu f2c9012cce Refactor installation and initialization logic, and expand test coverage
- install.py: Major update including configuration variable expansion, improved k3s/k3d handling, and enhanced installation logic.

- etc/ scripts: Significant refactoring of initialization scripts (Kerberos, Port Forwards, Garage Store, etc.).

- Port Forwards: Transitioned from XML to port-mappings.conf for managing kubectl port-forwards.

- Status Reporting: Improved status checking for common services.

- Infrastructure: Updated Ansible inventory and rsyslog role configurations.

- Tests: Added a comprehensive suite of tests for 'etc' initialization scripts in prole/tests/etc/.

- Documentation: Added prole-db-documentation-mcp-architecture.md.

- General: Updated Dockerfiles and various helper scripts.
2026-02-13 21:36:39 -08:00

701 lines
22 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# init_kdc.sh
# Purpose:
# - Provision the in-cluster Prole KDC (MIT Kerberos) in the common services namespace
# - Optionally configure cross-realm trust to an external realm when credentials are provided
#
# Usage:
# ./init_kdc.sh initialize|update # create/update KDC resources
# ./init_kdc.sh status # show KDC status
# ./init_kdc.sh cleanup # remove KDC resources
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# 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
prole_ensure_kubeconfig >/dev/null 2>&1 || true
ACTION=${1:-initialize}
KDC_NAMESPACE=${PROLE_KDC_NAMESPACE:-${SERVICE_NAMESPACE:-${NAMESPACE:-default}}}
PROLE_KDC_ENABLED=${PROLE_KDC_ENABLED:-1}
PROLE_KDC_NAME=${PROLE_KDC_NAME:-auth}
PROLE_KDC_SERVICE=${PROLE_KDC_SERVICE:-auth}
PROLE_KDC_IMAGE=${PROLE_KDC_IMAGE:-}
PROLE_KDC_IMAGE_NAME=${PROLE_KDC_IMAGE_NAME:-prole-authority}
PROLE_KDC_IMAGE_TAG=${PROLE_KDC_IMAGE_TAG:-latest}
PROLE_KDC_REGISTRY_HOST=${PROLE_KDC_REGISTRY_HOST:-${LOCAL_REGISTRY:-localhost:5000}}
PROLE_KDC_REGISTRY_INTERNAL=${PROLE_KDC_REGISTRY_INTERNAL:-${LOCAL_REGISTRY_INTERNAL:-}}
PROLE_KDC_BUILD_IMAGE=${PROLE_KDC_BUILD_IMAGE:-1}
PROLE_KDC_ROLLOUT_TIMEOUT=${PROLE_KDC_ROLLOUT_TIMEOUT:-5}
PROLE_KDC_DEPLOY_TIMEOUT=${PROLE_KDC_DEPLOY_TIMEOUT:-60}
PROLE_KDC_HOST_NETWORK=${PROLE_KDC_HOST_NETWORK:-}
PROLE_KDC_REALM=${PROLE_KDC_REALM:-}
PROLE_KDC_DOMAIN=${PROLE_KDC_DOMAIN:-}
PROLE_KDC_ADMIN_PRINCIPAL=${PROLE_KDC_ADMIN_PRINCIPAL:-admin/admin}
PROLE_KDC_ADMIN_PASSWORD=${PROLE_KDC_ADMIN_PASSWORD:-}
PROLE_KDC_MASTER_PASSWORD=${PROLE_KDC_MASTER_PASSWORD:-}
PROLE_KDC_TRUST_REALM=${PROLE_KDC_TRUST_REALM:-${KRB5_REALM:-}}
PROLE_KDC_TRUST_ADMIN=${PROLE_KDC_TRUST_ADMIN:-${KRB5_USER:-}}
PROLE_KDC_TRUST_PASSWORD=${PROLE_KDC_TRUST_PASSWORD:-${KRB5_PASSWORD:-}}
PROLE_KDC_TRUST_SHARED_PASSWORD=${PROLE_KDC_TRUST_SHARED_PASSWORD:-}
KRB5_KDC=${KRB5_KDC:-}
KRB5_ADMIN=${KRB5_ADMIN:-}
log() { printf '%s\n' "$*"; }
err() { printf '%s\n' "$*" >&2; }
ensure_tools() {
for t in kubectl; do
command -v "$t" >/dev/null || { err "Missing required tool: $t"; exit 1; }
done
}
ensure_docker() {
command -v docker >/dev/null || { err "Missing required tool: docker"; exit 1; }
if ! docker info >/dev/null 2>&1; then
err "Docker is not running or not accessible."
exit 1
fi
}
ensure_namespace() {
if ! kubectl get namespace "$KDC_NAMESPACE" >/dev/null 2>&1; then
log "Creating namespace '$KDC_NAMESPACE' ..."
kubectl create namespace "$KDC_NAMESPACE" >/dev/null 2>&1 || true
fi
}
normalized_mode() {
if command -v prole_normalize_mode >/dev/null 2>&1; then
prole_normalize_mode "${PROLE_MODE:-}"
return 0
fi
printf '%s' "${PROLE_MODE:-}"
}
is_k3d_mode() {
[[ "$(normalized_mode)" == "k3d" ]]
}
get_kdc_pods_with_containers() {
kubectl -n "$KDC_NAMESPACE" get pods -l "app=${PROLE_KDC_NAME}" \
-o jsonpath='{range .items[*]}{.metadata.name}{"|"}{range .spec.containers[*]}{.name}{" "}{end}{"\n"}{end}' 2>/dev/null || true
}
kdc_pods_missing_container() {
local rows line containers found c
rows=$(get_kdc_pods_with_containers)
[[ -z "$rows" ]] && return 1
while IFS= read -r line; do
[[ -z "$line" ]] && continue
containers="${line#*|}"
found=0
for c in $containers; do
if [[ "$c" == "kdc" ]]; then
found=1
break
fi
done
if [[ "$found" -eq 0 ]]; then
return 0
fi
done <<< "$rows"
return 1
}
kdc_multiple_active_replicasets() {
local rows line spec status count
rows=$(kubectl -n "$KDC_NAMESPACE" get rs -l "app=${PROLE_KDC_NAME}" \
-o jsonpath='{range .items[*]}{.metadata.name}{"|"}{.spec.replicas}{"|"}{.status.replicas}{"\n"}{end}' 2>/dev/null || true)
[[ -z "$rows" ]] && return 1
count=0
while IFS= read -r line; do
[[ -z "$line" ]] && continue
spec=$(printf '%s' "$line" | awk -F'|' '{print $2}')
status=$(printf '%s' "$line" | awk -F'|' '{print $3}')
spec=${spec:-0}
status=${status:-0}
if [[ "$spec" -gt 0 || "$status" -gt 0 ]]; then
count=$((count+1))
fi
done <<< "$rows"
(( count > 1 ))
}
kdc_deployment_not_ready() {
local desired ready updated
desired=$(kubectl -n "$KDC_NAMESPACE" get deploy "$PROLE_KDC_NAME" -o jsonpath='{.spec.replicas}' 2>/dev/null || true)
ready=$(kubectl -n "$KDC_NAMESPACE" get deploy "$PROLE_KDC_NAME" -o jsonpath='{.status.readyReplicas}' 2>/dev/null || true)
updated=$(kubectl -n "$KDC_NAMESPACE" get deploy "$PROLE_KDC_NAME" -o jsonpath='{.status.updatedReplicas}' 2>/dev/null || true)
desired=${desired:-0}
ready=${ready:-0}
updated=${updated:-0}
if [[ "$ready" -lt "$desired" || "$updated" -lt "$desired" ]]; then
return 0
fi
return 1
}
kdc_stale_deployment() {
if ! kdc_deployment_not_ready; then
return 1
fi
kdc_pods_missing_container && return 0
kdc_multiple_active_replicasets && return 0
return 1
}
maybe_cleanup_stale_kdc() {
local reason="${1:-stale}"
local policy="${2:-broad}"
if ! is_k3d_mode; then
return 1
fi
if ! kubectl -n "$KDC_NAMESPACE" get deploy "$PROLE_KDC_NAME" >/dev/null 2>&1; then
return 1
fi
if [[ "$policy" == "strict" ]]; then
if ! kdc_deployment_not_ready; then
return 1
fi
if ! kdc_pods_missing_container; then
return 1
fi
elif ! kdc_stale_deployment; then
return 1
fi
err "WARN: Detected stale Prole KDC deployment (${reason}). Cleaning up..."
cleanup_prole_kdc
return 0
}
lowercase() {
printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]'
}
registry_host_from_url() {
local value="${1:-}"
value="${value#http://}"
value="${value#https://}"
value="${value%%/*}"
value="${value%%:*}"
printf '%s' "$value"
}
gen_password() {
if command -v openssl >/dev/null 2>&1; then
openssl rand -base64 18
return 0
fi
if command -v python3 >/dev/null 2>&1; then
python3 - <<'PY'
import secrets, string
alphabet = string.ascii_letters + string.digits
print(''.join(secrets.choice(alphabet) for _ in range(24)))
PY
return 0
fi
date +%s
}
b64_decode() {
if base64 --decode </dev/null >/dev/null 2>&1; then
base64 --decode
return 0
fi
if base64 -d </dev/null >/dev/null 2>&1; then
base64 -d
return 0
fi
base64 -D
}
get_secret_value() {
local secret="$1"
local key="$2"
kubectl -n "$KDC_NAMESPACE" get secret "$secret" -o "jsonpath={.data.${key}}" 2>/dev/null | b64_decode 2>/dev/null || true
}
resolve_prole_kdc_defaults() {
if [[ -z "$PROLE_KDC_REALM" ]]; then
PROLE_KDC_REALM="PROLE.LOCAL"
fi
if [[ -z "$PROLE_KDC_DOMAIN" ]]; then
PROLE_KDC_DOMAIN=$(lowercase "$PROLE_KDC_REALM")
fi
local mode=""
if command -v prole_normalize_mode >/dev/null 2>&1; then
mode=$(prole_normalize_mode "${PROLE_MODE:-}")
else
mode="${PROLE_MODE:-}"
fi
local k3s_host=""
if [[ "$mode" == "k3s" ]]; then
k3s_host=$(registry_host_from_url "${PROLE_K3S_SERVER:-${K3S_SERVER_URL:-}}")
if [[ -n "$k3s_host" ]] && ([[ -z "${PROLE_KDC_REGISTRY_HOST:-}" ]] || [[ "$PROLE_KDC_REGISTRY_HOST" == "localhost:5000" ]] || [[ "$PROLE_KDC_REGISTRY_HOST" == *"k3d"* ]]); then
PROLE_KDC_REGISTRY_HOST="${k3s_host}:5000"
fi
fi
if [[ -z "$PROLE_KDC_REGISTRY_INTERNAL" ]]; then
if [[ -n "${KDC_NAMESPACE:-}" ]]; then
PROLE_KDC_REGISTRY_INTERNAL="registry.${KDC_NAMESPACE}.svc.cluster.local:5000"
elif [[ -n "${SERVICE_NAMESPACE:-}" ]]; then
PROLE_KDC_REGISTRY_INTERNAL="registry.${SERVICE_NAMESPACE}.svc.cluster.local:5000"
elif [[ -n "${NAMESPACE:-}" ]]; then
PROLE_KDC_REGISTRY_INTERNAL="registry.${NAMESPACE}.svc.cluster.local:5000"
fi
fi
if [[ "$mode" == "k3s" ]]; then
if [[ -n "$k3s_host" ]] && ([[ -z "$PROLE_KDC_REGISTRY_INTERNAL" ]] || [[ "$PROLE_KDC_REGISTRY_INTERNAL" == *"k3d"* ]] || [[ "$PROLE_KDC_REGISTRY_INTERNAL" == *".svc.cluster.local"* ]]); then
PROLE_KDC_REGISTRY_INTERNAL="${k3s_host}:5000"
fi
fi
if [[ -z "$PROLE_KDC_IMAGE" ]]; then
if [[ -n "$PROLE_KDC_REGISTRY_INTERNAL" ]]; then
PROLE_KDC_IMAGE="${PROLE_KDC_REGISTRY_INTERNAL}/${PROLE_KDC_IMAGE_NAME}:${PROLE_KDC_IMAGE_TAG}"
else
PROLE_KDC_IMAGE="${PROLE_KDC_IMAGE_NAME}:${PROLE_KDC_IMAGE_TAG}"
fi
fi
}
resolve_kdc_docker_dir() {
if [[ -n "${PROLE_KDC_DOCKER_DIR:-}" && -d "$PROLE_KDC_DOCKER_DIR" ]]; then
echo "$PROLE_KDC_DOCKER_DIR"
return 0
fi
if [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/prole/authority" ]]; then
echo "$PROLE_HOME/prole/authority"
return 0
fi
if [[ -d "$SCRIPT_DIR/../prole/authority" ]]; then
echo "$SCRIPT_DIR/../prole/authority"
return 0
fi
return 1
}
is_truthy() {
case "${1:-}" in
1|true|TRUE|True|yes|YES|Yes|on|ON|On) return 0 ;;
esac
return 1
}
build_prole_kdc_image() {
if ! is_truthy "${PROLE_KDC_BUILD_IMAGE:-1}"; then
return 0
fi
local docker_dir
docker_dir=$(resolve_kdc_docker_dir || true)
if [[ -z "$docker_dir" ]]; then
err "ERROR: prole/authority Docker context not found."
exit 1
fi
ensure_docker
local local_tag="${PROLE_KDC_IMAGE_NAME}:${PROLE_KDC_IMAGE_TAG}"
log "Building authority image: ${local_tag} (context: ${docker_dir}) ..."
docker build -t "$local_tag" "$docker_dir"
if [[ -n "$PROLE_KDC_REGISTRY_HOST" ]]; then
local remote_tag="${PROLE_KDC_REGISTRY_HOST}/${PROLE_KDC_IMAGE_NAME}:${PROLE_KDC_IMAGE_TAG}"
log "Tagging authority image for registry: ${remote_tag}"
docker tag "$local_tag" "$remote_tag"
log "Pushing authority image to registry: ${remote_tag}"
if ! docker push "$remote_tag"; then
if command -v skopeo >/dev/null 2>&1; then
log "Docker push failed; retrying with skopeo (insecure registry) ..."
skopeo copy --dest-tls-verify=false "docker-daemon:${local_tag}" "docker://${remote_tag}"
else
err "ERROR: docker push failed and skopeo is not available."
exit 1
fi
fi
fi
if [[ -n "$PROLE_KDC_REGISTRY_INTERNAL" ]]; then
PROLE_KDC_IMAGE="${PROLE_KDC_REGISTRY_INTERNAL}/${PROLE_KDC_IMAGE_NAME}:${PROLE_KDC_IMAGE_TAG}"
elif [[ -n "$PROLE_KDC_REGISTRY_HOST" ]]; then
PROLE_KDC_IMAGE="${PROLE_KDC_REGISTRY_HOST}/${PROLE_KDC_IMAGE_NAME}:${PROLE_KDC_IMAGE_TAG}"
else
PROLE_KDC_IMAGE="${local_tag}"
fi
}
ensure_prole_kdc_secrets() {
local secret_name="prole-kdc-secrets"
if [[ -z "$PROLE_KDC_ADMIN_PASSWORD" ]]; then
PROLE_KDC_ADMIN_PASSWORD=$(get_secret_value "$secret_name" "admin_password")
fi
if [[ -z "$PROLE_KDC_MASTER_PASSWORD" ]]; then
PROLE_KDC_MASTER_PASSWORD=$(get_secret_value "$secret_name" "master_password")
fi
if [[ -z "$PROLE_KDC_TRUST_SHARED_PASSWORD" ]]; then
PROLE_KDC_TRUST_SHARED_PASSWORD=$(get_secret_value "$secret_name" "trust_shared_password")
fi
if [[ -z "$PROLE_KDC_TRUST_PASSWORD" ]]; then
PROLE_KDC_TRUST_PASSWORD=$(get_secret_value "$secret_name" "trust_password")
fi
if [[ -z "$PROLE_KDC_ADMIN_PASSWORD" ]]; then
PROLE_KDC_ADMIN_PASSWORD=$(gen_password)
fi
if [[ -z "$PROLE_KDC_MASTER_PASSWORD" ]]; then
PROLE_KDC_MASTER_PASSWORD=$(gen_password)
fi
if [[ -z "$PROLE_KDC_TRUST_SHARED_PASSWORD" ]]; then
PROLE_KDC_TRUST_SHARED_PASSWORD="$PROLE_KDC_MASTER_PASSWORD"
fi
kubectl -n "$KDC_NAMESPACE" create secret generic "$secret_name" \
--from-literal=admin_password="$PROLE_KDC_ADMIN_PASSWORD" \
--from-literal=master_password="$PROLE_KDC_MASTER_PASSWORD" \
--from-literal=trust_shared_password="$PROLE_KDC_TRUST_SHARED_PASSWORD" \
--from-literal=trust_password="$PROLE_KDC_TRUST_PASSWORD" \
--dry-run=client -o yaml | kubectl apply -f - >/dev/null
}
ensure_prole_kdc() {
if [[ "$PROLE_KDC_ENABLED" == "0" || "$PROLE_KDC_ENABLED" == "false" || "$PROLE_KDC_ENABLED" == "False" ]]; then
log "Prole KDC disabled (PROLE_KDC_ENABLED=$PROLE_KDC_ENABLED)."
return 0
fi
if [[ -z "${PROLE_KDC_HOST_NETWORK}" && "$(normalized_mode)" == "k3d" ]]; then
PROLE_KDC_HOST_NETWORK=1
fi
resolve_prole_kdc_defaults
build_prole_kdc_image
ensure_prole_kdc_secrets
local deployment_present=0
if kubectl -n "$KDC_NAMESPACE" get deploy "$PROLE_KDC_NAME" >/dev/null 2>&1; then
deployment_present=1
fi
# Clean up legacy names if we're switching to the new auth naming.
if [[ "$PROLE_KDC_NAME" != "dog" ]]; then
kubectl -n "$KDC_NAMESPACE" delete deployment dog --ignore-not-found >/dev/null 2>&1 || true
fi
if [[ "$PROLE_KDC_SERVICE" != "authority" ]]; then
kubectl -n "$KDC_NAMESPACE" delete service authority --ignore-not-found >/dev/null 2>&1 || true
fi
local admin_acl_principal="$PROLE_KDC_ADMIN_PRINCIPAL"
if [[ "$admin_acl_principal" != *"@"* ]]; then
admin_acl_principal="${admin_acl_principal}@${PROLE_KDC_REALM}"
fi
local trust_block=""
if [[ -n "$PROLE_KDC_TRUST_REALM" && "$PROLE_KDC_TRUST_REALM" != "$PROLE_KDC_REALM" && -n "$KRB5_KDC" ]]; then
local trust_admin_server="${KRB5_ADMIN:-$KRB5_KDC}"
trust_block=$(cat <<EOF
${PROLE_KDC_TRUST_REALM} = {
kdc = ${KRB5_KDC}
admin_server = ${trust_admin_server}
}
[capaths]
${PROLE_KDC_REALM} = {
${PROLE_KDC_TRUST_REALM} = .
}
${PROLE_KDC_TRUST_REALM} = {
${PROLE_KDC_REALM} = .
}
EOF
)
fi
apply_kdc_manifest() {
log "Applying Prole KDC '${PROLE_KDC_NAME}' in namespace '${KDC_NAMESPACE}' (realm ${PROLE_KDC_REALM}) ..."
local host_net_block=""
local dns_policy_block=""
if is_truthy "${PROLE_KDC_HOST_NETWORK:-0}"; then
host_net_block=" hostNetwork: true"
dns_policy_block=" dnsPolicy: ClusterFirstWithHostNet"
fi
cat <<EOF | kubectl apply -n "$KDC_NAMESPACE" -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: prole-kdc-config
namespace: ${KDC_NAMESPACE}
data:
krb5.conf: |
[libdefaults]
default_realm = ${PROLE_KDC_REALM}
dns_lookup_realm = false
dns_lookup_kdc = false
[realms]
${PROLE_KDC_REALM} = {
kdc = 127.0.0.1
admin_server = 127.0.0.1
}${trust_block}
kdc.conf: |
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
[realms]
${PROLE_KDC_REALM} = {
database_name = /var/lib/krb5kdc/principal
admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
acl_file = /etc/krb5kdc/kadm5.acl
key_stash_file = /etc/krb5kdc/stash
max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
default_principal_flags = +preauth
}
kadm5.acl: |
${admin_acl_principal} *
entrypoint.sh: |
#!/usr/bin/env bash
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
if ! command -v krb5kdc >/dev/null 2>&1; then
echo "Installing Kerberos packages..."
echo "krb5-config krb5-config/default_realm string ${PROLE_KDC_REALM}" | debconf-set-selections || true
echo "krb5-config krb5-config/kerberos_servers string 127.0.0.1" | debconf-set-selections || true
echo "krb5-config krb5-config/admin_server string 127.0.0.1" | debconf-set-selections || true
apt-get update
apt-get install -y --no-install-recommends krb5-kdc krb5-admin-server krb5-user dnsutils ca-certificates
rm -rf /var/lib/apt/lists/*
fi
mkdir -p /etc/krb5kdc /var/lib/krb5kdc
if [[ -f /opt/prole-kdc/krb5.conf ]]; then
cp /opt/prole-kdc/krb5.conf /etc/krb5.conf
fi
if [[ -f /opt/prole-kdc/kdc.conf ]]; then
cp /opt/prole-kdc/kdc.conf /etc/krb5kdc/kdc.conf
fi
if [[ -f /opt/prole-kdc/kadm5.acl ]]; then
cp /opt/prole-kdc/kadm5.acl /etc/krb5kdc/kadm5.acl
fi
realm="\${PROLE_KDC_REALM}"
admin_principal="\${PROLE_KDC_ADMIN_PRINCIPAL}"
if [[ "\${admin_principal}" != *"@"* ]]; then
admin_principal="\${admin_principal}@\${PROLE_KDC_REALM}"
fi
if [[ ! -f /var/lib/krb5kdc/principal ]]; then
echo "Initializing realm database for \${PROLE_KDC_REALM}..."
kdb5_util create -s -r "\${realm}" -P "\${PROLE_KDC_MASTER_PASSWORD}"
fi
if ! kadmin.local -q "get_principal \${admin_principal}" >/dev/null 2>&1; then
echo "Creating admin principal \${admin_principal}..."
kadmin.local -q "addprinc -pw \${PROLE_KDC_ADMIN_PASSWORD} \${admin_principal}"
fi
if [[ -n "\${PROLE_KDC_TRUST_REALM:-}" && "\${PROLE_KDC_TRUST_REALM}" != "\${PROLE_KDC_REALM}" ]]; then
shared_pw="\${PROLE_KDC_TRUST_SHARED_PASSWORD:-\${PROLE_KDC_MASTER_PASSWORD}}"
if ! kadmin.local -q "get_principal krbtgt/\${PROLE_KDC_TRUST_REALM}@\${PROLE_KDC_REALM}" >/dev/null 2>&1; then
echo "Creating trust principal krbtgt/\${PROLE_KDC_TRUST_REALM}@\${PROLE_KDC_REALM}..."
kadmin.local -q "addprinc -pw \${shared_pw} krbtgt/\${PROLE_KDC_TRUST_REALM}@\${PROLE_KDC_REALM}"
fi
if [[ -n "\${PROLE_KDC_TRUST_ADMIN:-}" && -n "\${PROLE_KDC_TRUST_PASSWORD:-}" ]]; then
echo "Creating reciprocal trust principal in \${PROLE_KDC_TRUST_REALM}..."
kadmin -r "\${PROLE_KDC_TRUST_REALM}" -p "\${PROLE_KDC_TRUST_ADMIN}" -w "\${PROLE_KDC_TRUST_PASSWORD}" \
-q "addprinc -pw \${shared_pw} krbtgt/\${PROLE_KDC_REALM}@\${PROLE_KDC_TRUST_REALM}" || true
else
echo "WARN: Missing PROLE_KDC_TRUST_ADMIN/PROLE_KDC_TRUST_PASSWORD; skipping external trust principal."
fi
fi
krb5kdc
exec kadmind -nofork
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${PROLE_KDC_NAME}
namespace: ${KDC_NAMESPACE}
spec:
replicas: 1
selector:
matchLabels:
app: ${PROLE_KDC_NAME}
template:
metadata:
labels:
app: ${PROLE_KDC_NAME}
spec:
${host_net_block}
${dns_policy_block}
containers:
- name: kdc
image: ${PROLE_KDC_IMAGE}
command: ["/bin/bash", "/opt/prole-kdc/entrypoint.sh"]
env:
- name: PROLE_KDC_REALM
value: "${PROLE_KDC_REALM}"
- name: PROLE_KDC_ADMIN_PRINCIPAL
value: "${PROLE_KDC_ADMIN_PRINCIPAL}"
- name: PROLE_KDC_MASTER_PASSWORD
valueFrom:
secretKeyRef:
name: prole-kdc-secrets
key: master_password
- name: PROLE_KDC_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: prole-kdc-secrets
key: admin_password
- name: PROLE_KDC_TRUST_SHARED_PASSWORD
valueFrom:
secretKeyRef:
name: prole-kdc-secrets
key: trust_shared_password
- name: PROLE_KDC_TRUST_REALM
value: "${PROLE_KDC_TRUST_REALM}"
- name: PROLE_KDC_TRUST_ADMIN
value: "${PROLE_KDC_TRUST_ADMIN}"
- name: PROLE_KDC_TRUST_PASSWORD
valueFrom:
secretKeyRef:
name: prole-kdc-secrets
key: trust_password
ports:
- name: krb5-udp
containerPort: 88
protocol: UDP
- name: krb5-tcp
containerPort: 88
protocol: TCP
- name: kpasswd-udp
containerPort: 464
protocol: UDP
- name: kpasswd-tcp
containerPort: 464
protocol: TCP
- name: kadmin
containerPort: 749
protocol: TCP
volumeMounts:
- name: prole-kdc-config
mountPath: /opt/prole-kdc
- name: prole-kdc-data
mountPath: /var/lib/krb5kdc
- name: prole-kdc-data
mountPath: /etc/krb5kdc
volumes:
- name: prole-kdc-config
configMap:
name: prole-kdc-config
- name: prole-kdc-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: ${PROLE_KDC_SERVICE}
namespace: ${KDC_NAMESPACE}
spec:
selector:
app: ${PROLE_KDC_NAME}
ports:
- name: krb5-udp
port: 88
targetPort: 88
protocol: UDP
- name: krb5-tcp
port: 88
targetPort: 88
protocol: TCP
- name: kpasswd-udp
port: 464
targetPort: 464
protocol: UDP
- name: kpasswd-tcp
port: 464
targetPort: 464
protocol: TCP
- name: kadmin
port: 749
targetPort: 749
protocol: TCP
EOF
}
apply_kdc_manifest
local rollout_timeout="$PROLE_KDC_ROLLOUT_TIMEOUT"
if [[ "$deployment_present" -eq 0 ]]; then
rollout_timeout="$PROLE_KDC_DEPLOY_TIMEOUT"
fi
if ! kubectl -n "$KDC_NAMESPACE" rollout status deploy/${PROLE_KDC_NAME} --timeout="${rollout_timeout}s"; then
err "WARN: Prole KDC rollout did not complete within ${rollout_timeout}s."
if maybe_cleanup_stale_kdc "rollout timeout"; then
log "Re-applying Prole KDC after cleanup..."
apply_kdc_manifest
kubectl -n "$KDC_NAMESPACE" rollout status deploy/${PROLE_KDC_NAME} --timeout="${PROLE_KDC_DEPLOY_TIMEOUT}s" || true
fi
fi
}
cleanup_prole_kdc() {
log "Removing Prole KDC resources (if present)..."
kubectl -n "$KDC_NAMESPACE" delete service "$PROLE_KDC_SERVICE" --ignore-not-found
kubectl -n "$KDC_NAMESPACE" delete deployment "$PROLE_KDC_NAME" --ignore-not-found
kubectl -n "$KDC_NAMESPACE" delete configmap prole-kdc-config --ignore-not-found
}
status() {
log "--- init_kdc status ---"
log "Namespace: $KDC_NAMESPACE"
log "Prole KDC enabled: ${PROLE_KDC_ENABLED:-0}"
log "Prole KDC realm: ${PROLE_KDC_REALM:-<unset>}"
log "Prole KDC service: ${PROLE_KDC_SERVICE:-<unset>}"
log "Prole KDC image: ${PROLE_KDC_IMAGE:-<unset>}"
if kubectl -n "$KDC_NAMESPACE" get deploy "$PROLE_KDC_NAME" >/dev/null 2>&1; then
log "[OK] Prole KDC deployment present"
if maybe_cleanup_stale_kdc "status check" "strict"; then
log "[INFO] Stale Prole KDC deployment removed. Re-run init_kdc.sh update to recreate."
fi
else
log "[INFO] Prole KDC deployment not present"
fi
}
case "$ACTION" in
initialize|init|update|deploy|start)
ensure_tools
ensure_namespace
ensure_prole_kdc
;;
status)
ensure_tools
status
;;
cleanup|delete|remove)
ensure_tools
ensure_namespace
cleanup_prole_kdc
;;
*)
err "Usage: $0 {initialize|update|status|cleanup}"
exit 2
;;
esac