prole/etc/init_knoe_auth.sh
chrisfu a069989315 Rename prole-db to knoe-db, add knoe-auth as cluster-internal KDC
Itemized changes:

1. knoe-auth: New cluster-internal KDC and SSO gateway service
   - Created etc/init_knoe_auth.sh based on init_kdc.sh with knoe-auth naming
   - Namespace defaults to SERVICE_NAMESPACE (knoe-system)
   - ConfigMap: knoe-auth-kdc-config, Secret: knoe-auth-secrets
   - Legacy cleanup removes old auth/dog/authority deployments

2. Orchestration: knoe-auth initializes before CloudNativePG
   - Updated prole.sh to insert init_knoe_auth.sh as step 2 (before CNPG)
   - Renumbered all subsequent initialization steps

3. Kong routing: Updated init_kong.sh to route to knoe-auth in SERVICE_NAMESPACE

4. Comment/reference updates for knoe-auth
   - Updated init_common_services.sh, init_service_layer.sh, init_kerberos.sh

5. prole-db renamed to knoe-db across the entire codebase
   - Renamed prole-db/ directory to knoe-db/
   - Renamed all prole-db Kubernetes manifests (deploy/opentofu, k8s/)
   - Renamed scripts: docker-root-knoe-db.sh, docker-run-knoe-db.sh, test-cnpg-knoe-db.sh
   - Renamed etc/init_prole-db-reset.sh to etc/init_knoe-db-reset.sh
   - Renamed etc/prole-db-passwwd.sh to etc/knoe-db-passwwd.sh
   - Renamed mock_val counterparts accordingly
   - Renamed tests/etc/test_init_prole-db-reset.sh to test_init_knoe-db-reset.sh
   - Renamed docs/prole-db-documentation-mcp-architecture.md to knoe-db variant
   - Renamed modes/k3d/prole-db/ to modes/k3d/knoe-db/
   - Renamed prole-db.iml to knoe-db.iml

6. Configuration updates
   - Updated conf/dev, conf/prod, conf/test, conf/service prole.cfg files
   - Updated conf/port-mapping.cfg
   - Updated etc/prole_cfg.sh and mock_val/prole_cfg.sh
   - Updated service/prole.cfg

7. Kubernetes manifests and deploy configuration
   - Updated deploy/opentofu/k3s ArgoCD application YAMLs
   - Updated kong-configmap.yaml and kustomization.yaml
   - Updated k3s/kong-config.yml and prole-resources.yaml
   - Updated prole-mssql-db deployment YAMLs
   - Updated supabase helm render and deploy scripts

8. Infrastructure and GCP Terraform
   - Updated deploy/gcp/terraform: folders, groups, IAM, service-projects

9. Python/installer code updates
   - Updated knoe/core: actions, build_context, controller, env, milestones
   - Updated knoe/milestone.py
   - Updated knoe/ui/screens: cfg, database, database_options, deploy, docker,
     navigation, security, services, validate
   - Updated knoe.spec, status.py

10. Shell script updates
    - Updated etc/: build_db, init_cloudnative_pg, init_cnpg_backup,
      init_db_manager, init_forgejo, init_gitlab, init_monitoring, init_openbao,
      init_port_forwards, init_postgrest, init_supabase_ports, status
    - Updated mock_val/ counterparts for all above scripts
    - Updated prole-net/init-prole-dns.sh
    - Updated bin/prole-kpf.sh, gitea/deploy.sh, supabase/deploy.sh

11. Test updates
    - Updated tests/etc/: test_init_cloudnative_pg*, test_init_cnpg_backup*,
      test_init_kdc*, test_init_kerberos*, test_init_kong*, test_prole_cfg*
    - Updated tests/installer/: test_actions_helpers, test_cfg_save_kubecontext,
      test_controller, test_core_classes, test_milestones, test_milestones_extended,
      test_namespace_propagation
    - Updated tests/: test_database_options, test_navigation,
      test_render_supabase_hostname, test_docker_build_fix,
      test_all_prole_home_fixes, silent_install_test, final_test

12. Documentation updates
    - Updated docs/: DOCKER-BUILD-FIX, PROLE-CFG-SECRETS, PROLE-HOME-DIRECTORY,
      build-system, patent
    - Updated scan/network_description.txt
    - Updated pom.xml

13. Miscellaneous script updates
    - Updated root-level: _adopt_replica_pvcs, _fix_replica_merlin, _import_pi,
      _patch_cluster, _prebind_pvcs, _rebind_d002, _rebind_d002b, test_resolve
    - Updated scripts/generate_spec.py

Co-authored-by: Junie <junie@jetbrains.com>
2026-03-22 22:16:21 -07:00

886 lines
30 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
# init_knoe_auth.sh
# Purpose:
# - Provision the knoe-auth service (cluster-internal KDC + SSO gateway) in the
# service namespace (knoe-system by default)
# - knoe-auth acts as the authentication server trusted by CNPG and other cluster
# services, and hosts the SSO gateway pod
# - Optionally configure cross-realm trust to an external realm when credentials are provided
# - Must complete before init_cloudnative_pg.sh so the database can depend on it
#
# Usage:
# ./init_knoe_auth.sh initialize|update # create/update knoe-auth resources
# ./init_knoe_auth.sh status # show knoe-auth status
# ./init_knoe_auth.sh cleanup # remove knoe-auth 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
prole_ensure_kube_context || exit 1
ACTION=${1:-initialize}
KNOE_AUTH_NAMESPACE=${KNOE_AUTH_NAMESPACE:-${SERVICE_NAMESPACE:-${NAMESPACE:-default}}}
KDC_NAMESPACE="$KNOE_AUTH_NAMESPACE"
KNOE_AUTH_ENABLED=${KNOE_AUTH_ENABLED:-${PROLE_KDC_ENABLED:-1}}
KNOE_AUTH_NAME=${KNOE_AUTH_NAME:-knoe-auth}
KNOE_AUTH_SERVICE=${KNOE_AUTH_SERVICE:-knoe-auth}
KNOE_AUTH_IMAGE=${KNOE_AUTH_IMAGE:-${PROLE_KDC_IMAGE:-}}
# If the user provided an explicit image, we should not require Docker unless
# they explicitly opt into building.
KNOE_AUTH_IMAGE_EXPLICIT=0
if [[ -n "${KNOE_AUTH_IMAGE:-}" ]]; then
KNOE_AUTH_IMAGE_EXPLICIT=1
fi
KNOE_AUTH_IMAGE_NAME=${KNOE_AUTH_IMAGE_NAME:-${PROLE_KDC_IMAGE_NAME:-prole-authority}}
KNOE_AUTH_IMAGE_TAG=${KNOE_AUTH_IMAGE_TAG:-${PROLE_KDC_IMAGE_TAG:-latest}}
KNOE_AUTH_REGISTRY_HOST=${KNOE_AUTH_REGISTRY_HOST:-${PROLE_KDC_REGISTRY_HOST:-${LOCAL_REGISTRY:-localhost:5000}}}
KNOE_AUTH_REGISTRY_INTERNAL=${KNOE_AUTH_REGISTRY_INTERNAL:-${PROLE_KDC_REGISTRY_INTERNAL:-${LOCAL_REGISTRY_INTERNAL:-}}}
KNOE_AUTH_BUILD_IMAGE_SET=0
if [[ -n "${KNOE_AUTH_BUILD_IMAGE+x}" ]]; then
KNOE_AUTH_BUILD_IMAGE_SET=1
elif [[ -n "${PROLE_KDC_BUILD_IMAGE+x}" ]]; then
KNOE_AUTH_BUILD_IMAGE_SET=1
fi
KNOE_AUTH_BUILD_IMAGE=${KNOE_AUTH_BUILD_IMAGE:-${PROLE_KDC_BUILD_IMAGE:-1}}
KNOE_AUTH_ROLLOUT_TIMEOUT=${KNOE_AUTH_ROLLOUT_TIMEOUT:-${PROLE_KDC_ROLLOUT_TIMEOUT:-5}}
KNOE_AUTH_DEPLOY_TIMEOUT=${KNOE_AUTH_DEPLOY_TIMEOUT:-${PROLE_KDC_DEPLOY_TIMEOUT:-60}}
KNOE_AUTH_HOST_NETWORK=${KNOE_AUTH_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:-}
local_registry_enabled() {
local raw="${PROLE_ENABLE_LOCAL_REGISTRY:-${ENABLE_LOCAL_REGISTRY:-}}"
if [[ -n "$raw" ]]; then
case "$raw" in
1|true|TRUE|True|yes|YES|Yes|on|ON|On) return 0 ;;
esac
return 1
fi
local mode=""
if command -v prole_normalize_mode >/dev/null 2>&1; then
mode=$(prole_normalize_mode "${PROLE_MODE:-${DEPLOYMENT_MODE:-${CLUSTER_ENV:-}}}")
else
mode="${PROLE_MODE:-${DEPLOYMENT_MODE:-${CLUSTER_ENV:-}}}"
fi
[[ "$mode" == "k3d" || "$mode" == "k3s" ]]
}
if ! local_registry_enabled; then
# Only clear default local-registry settings; preserve explicit registry host values.
_default_host="${LOCAL_REGISTRY:-localhost:5000}"
if [[ -z "${KNOE_AUTH_REGISTRY_HOST:-}" || "${KNOE_AUTH_REGISTRY_HOST:-}" == "$_default_host" ]]; then
KNOE_AUTH_REGISTRY_HOST=""
fi
KNOE_AUTH_REGISTRY_INTERNAL=""
unset _default_host
fi
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."
err "This is required to build/push the knoe-auth image."
err "Start Docker (e.g. Docker Desktop), or set KNOE_AUTH_IMAGE to a prebuilt image and/or set KNOE_AUTH_BUILD_IMAGE=0."
exit 1
fi
}
docker_available() {
command -v docker >/dev/null 2>&1 || return 1
docker info >/dev/null 2>&1
}
resolve_knoe_auth_image() {
# Ensure we have a deterministic image reference even when skipping local builds.
if [[ -n "${KNOE_AUTH_IMAGE:-}" ]]; then
return 0
fi
if [[ -n "${KNOE_AUTH_REGISTRY_INTERNAL:-}" ]]; then
KNOE_AUTH_IMAGE="${KNOE_AUTH_REGISTRY_INTERNAL}/${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_IMAGE_TAG}"
return 0
fi
if [[ -n "${KNOE_AUTH_REGISTRY_HOST:-}" ]]; then
KNOE_AUTH_IMAGE="${KNOE_AUTH_REGISTRY_HOST}/${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_IMAGE_TAG}"
return 0
fi
KNOE_AUTH_IMAGE="${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_IMAGE_TAG}"
}
ensure_namespace() {
if ! kubectl get namespace "$KNOE_AUTH_NAMESPACE" >/dev/null 2>&1; then
log "Creating namespace '$KNOE_AUTH_NAMESPACE' ..."
kubectl create namespace "$KNOE_AUTH_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 "$KNOE_AUTH_NAMESPACE" get pods -l "app=${KNOE_AUTH_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 "$KNOE_AUTH_NAMESPACE" get rs -l "app=${KNOE_AUTH_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 "$KNOE_AUTH_NAMESPACE" get deploy "$KNOE_AUTH_NAME" -o jsonpath='{.spec.replicas}' 2>/dev/null || true)
ready=$(kubectl -n "$KNOE_AUTH_NAMESPACE" get deploy "$KNOE_AUTH_NAME" -o jsonpath='{.status.readyReplicas}' 2>/dev/null || true)
updated=$(kubectl -n "$KNOE_AUTH_NAMESPACE" get deploy "$KNOE_AUTH_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 "$KNOE_AUTH_NAMESPACE" get deploy "$KNOE_AUTH_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 knoe-auth KDC deployment (${reason}). Cleaning up..."
cleanup_knoe_auth
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 "$KNOE_AUTH_NAMESPACE" get secret "$secret" -o "jsonpath={.data.${key}}" 2>/dev/null | b64_decode 2>/dev/null || true
}
resolve_knoe_auth_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 local_registry_enabled; then
if [[ "$mode" == "k3s" ]]; then
k3s_host=$(registry_host_from_url "${PROLE_K3S_SERVER:-${K3S_SERVER_URL:-}}")
if [[ -n "$k3s_host" ]] && ([[ -z "${KNOE_AUTH_REGISTRY_HOST:-}" ]] || [[ "$KNOE_AUTH_REGISTRY_HOST" == "localhost:5000" ]] || [[ "$KNOE_AUTH_REGISTRY_HOST" == *"k3d"* ]]); then
KNOE_AUTH_REGISTRY_HOST="${k3s_host}:5000"
fi
fi
if [[ -z "$KNOE_AUTH_REGISTRY_INTERNAL" ]]; then
local reg_ns="${REGISTRY_NAMESPACE:-${SERVICE_NAMESPACE:-${NAMESPACE:-default}}}"
KNOE_AUTH_REGISTRY_INTERNAL="registry.${reg_ns}.svc.cluster.local:5000"
unset reg_ns
fi
else
KNOE_AUTH_REGISTRY_INTERNAL=""
fi
if [[ -z "$KNOE_AUTH_IMAGE" ]]; then
if [[ -n "$KNOE_AUTH_REGISTRY_INTERNAL" ]]; then
KNOE_AUTH_IMAGE="${KNOE_AUTH_REGISTRY_INTERNAL}/${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_IMAGE_TAG}"
else
KNOE_AUTH_IMAGE="${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_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 [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/authority" ]]; then
echo "$PROLE_HOME/authority"
return 0
fi
if [[ -d "$SCRIPT_DIR/../prole/authority" ]]; then
echo "$SCRIPT_DIR/../prole/authority"
return 0
fi
if [[ -d "$SCRIPT_DIR/../authority" ]]; then
echo "$SCRIPT_DIR/../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_knoe_auth_image() {
# If the user explicitly sets KNOE_AUTH_BUILD_IMAGE, honor it.
# Otherwise, skip building when an explicit image was provided.
if [[ "$KNOE_AUTH_BUILD_IMAGE_SET" == "1" ]]; then
if ! is_truthy "${KNOE_AUTH_BUILD_IMAGE:-0}"; then
resolve_knoe_auth_image
return 0
fi
else
if [[ "$KNOE_AUTH_IMAGE_EXPLICIT" == "1" ]]; then
log "Using preconfigured KNOE_AUTH_IMAGE='${KNOE_AUTH_IMAGE}'; skipping local image build."
return 0
fi
fi
if ! docker_available; then
# If the user forced a build, we must fail with a clear error.
if [[ "$KNOE_AUTH_BUILD_IMAGE_SET" == "1" ]]; then
ensure_docker
fi
log "[WARN] Docker is not available; skipping knoe-auth image build."
log " Set KNOE_AUTH_BUILD_IMAGE=1 to force building (requires Docker), or set KNOE_AUTH_IMAGE to a prebuilt image."
resolve_knoe_auth_image
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="${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_IMAGE_TAG}"
log "Building authority image: ${local_tag} (context: ${docker_dir}) ..."
docker build -t "$local_tag" "$docker_dir"
if [[ -n "$KNOE_AUTH_REGISTRY_HOST" ]]; then
local remote_tag="${KNOE_AUTH_REGISTRY_HOST}/${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_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 [[ -z "$KNOE_AUTH_REGISTRY_HOST" && "$(normalized_mode)" == "k3d" ]]; then
if command -v k3d >/dev/null 2>&1; then
local cluster_name="${K3D_CLUSTER_NAME:-knoe-dev-cluster}"
log "Importing authority image into k3d cluster: ${cluster_name}"
k3d image import "$local_tag" -c "$cluster_name" >/dev/null 2>&1 || true
fi
fi
if [[ -z "$KNOE_AUTH_REGISTRY_HOST" && "$(normalized_mode)" == "k3s" ]]; then
err "ERROR: No registry host configured for k3s; cannot publish authority image."
err " Set PROLE_K3S_SERVER (so the script can infer <host>:5000) or set KNOE_AUTH_REGISTRY_HOST explicitly."
exit 1
fi
if [[ -n "$KNOE_AUTH_REGISTRY_INTERNAL" ]]; then
KNOE_AUTH_IMAGE="${KNOE_AUTH_REGISTRY_INTERNAL}/${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_IMAGE_TAG}"
elif [[ -n "$KNOE_AUTH_REGISTRY_HOST" ]]; then
KNOE_AUTH_IMAGE="${KNOE_AUTH_REGISTRY_HOST}/${KNOE_AUTH_IMAGE_NAME}:${KNOE_AUTH_IMAGE_TAG}"
else
KNOE_AUTH_IMAGE="${local_tag}"
fi
}
ensure_knoe_auth_secrets() {
local secret_name="knoe-auth-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 "$KNOE_AUTH_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_knoe_auth() {
if [[ "$KNOE_AUTH_ENABLED" == "0" || "$KNOE_AUTH_ENABLED" == "false" || "$KNOE_AUTH_ENABLED" == "False" ]]; then
log "knoe-auth disabled (KNOE_AUTH_ENABLED=$KNOE_AUTH_ENABLED)."
return 0
fi
if [[ -z "${KNOE_AUTH_HOST_NETWORK}" && "$(normalized_mode)" == "k3d" ]]; then
KNOE_AUTH_HOST_NETWORK=1
fi
resolve_knoe_auth_defaults
build_knoe_auth_image
ensure_knoe_auth_secrets
local deployment_present=0
if kubectl -n "$KNOE_AUTH_NAMESPACE" get deploy "$KNOE_AUTH_NAME" >/dev/null 2>&1; then
deployment_present=1
fi
# Clean up legacy prole-auth / old KDC names when switching to knoe-auth.
kubectl -n "$KNOE_AUTH_NAMESPACE" delete deployment auth --ignore-not-found >/dev/null 2>&1 || true
kubectl -n "$KNOE_AUTH_NAMESPACE" delete service auth --ignore-not-found >/dev/null 2>&1 || true
kubectl -n "$KNOE_AUTH_NAMESPACE" delete deployment dog --ignore-not-found >/dev/null 2>&1 || true
kubectl -n "$KNOE_AUTH_NAMESPACE" delete service authority --ignore-not-found >/dev/null 2>&1 || true
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_knoe_auth_manifest() {
log "Applying knoe-auth '${KNOE_AUTH_NAME}' in namespace '${KNOE_AUTH_NAMESPACE}' (realm ${PROLE_KDC_REALM}) ..."
local host_net_block=""
local dns_policy_block=""
if is_truthy "${KNOE_AUTH_HOST_NETWORK:-0}"; then
host_net_block=" hostNetwork: true"
dns_policy_block=" dnsPolicy: ClusterFirstWithHostNet"
fi
cat <<EOF | kubectl apply -n "$KNOE_AUTH_NAMESPACE" -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: knoe-auth-kdc-config
namespace: ${KNOE_AUTH_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
# Enable verbose debug if requested
if [[ "${PROLE_KDC_DEBUG:-}" == "1" ]]; then
set -x
echo "[DEBUG] Environment snapshot:" >&2
env | sed -E 's/(PASSWORD|TOKEN|SECRET)=.*/\1=****/g' >&2 || true
fi
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/knoe-auth-kdc/krb5.conf ]]; then
cp /opt/knoe-auth-kdc/krb5.conf /etc/krb5.conf
fi
if [[ -f /opt/knoe-auth-kdc/kdc.conf ]]; then
cp /opt/knoe-auth-kdc/kdc.conf /etc/krb5kdc/kdc.conf
fi
if [[ -f /opt/knoe-auth-kdc/kadm5.acl ]]; then
cp /opt/knoe-auth-kdc/kadm5.acl /etc/krb5kdc/kadm5.acl
fi
# Validate required secrets early to avoid silent crashes
if [[ -z "${PROLE_KDC_MASTER_PASSWORD:-}" ]]; then
echo "ERROR: Missing required env PROLE_KDC_MASTER_PASSWORD (secret 'knoe-auth-secrets/master_password')." >&2
exit 1
fi
if [[ -z "${PROLE_KDC_ADMIN_PASSWORD:-}" ]]; then
echo "ERROR: Missing required env PROLE_KDC_ADMIN_PASSWORD (secret 'knoe-auth-secrets/admin_password')." >&2
exit 1
fi
# Optionally generate a minimal Samba configuration if a child realm is provided
realm="\${PROLE_CHILD_REALM:-}"
if [[ -z "\$realm" ]]; then
realm="\${PROLE_KDC_REALM}"
fi
if [[ -n "\$realm" ]]; then
workgroup="\${PROLE_CHILD_WORKGROUP:-}"
if [[ -z "\$workgroup" ]]; then
workgroup="\${realm%%.*}"
fi
netbios="\${PROLE_CHILD_NETBIOS_NAME:-}"
if [[ -z "\$netbios" ]]; then
netbios="\$workgroup"
fi
server_string="\${PROLE_CHILD_SERVER_STRING:-}"
if [[ -z "\$server_string" ]]; then
server_string="\${realm} AD DC"
fi
server_role="\${PROLE_SAMBA_SERVER_ROLE:-}"
if [[ -z "\$server_role" ]]; then
server_role='active directory domain controller'
fi
mkdir -p /etc/samba
# Write minimal Samba config without using a here‑doc to avoid YAML indentation issues
# when this script is embedded in a ConfigMap. Variables are expanded at container runtime.
{
printf '%s\n' "[global]"
printf '%s\n' " workgroup = \${workgroup}"
printf '%s\n' " realm = \${realm}"
printf '%s\n' " netbios name = \${netbios}"
printf '%s\n' " server string = \${server_string}"
printf '%s\n' " server role = \${server_role}"
} > /etc/samba/smb.conf
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
# Start daemons. Keep kadmind in PID 1; run krb5kdc in background and verify it binds.
echo "Starting krb5kdc and kadmind ..."
krb5kdc -n &
sleep 0.5
if ! pgrep -x krb5kdc >/dev/null 2>&1; then
echo "ERROR: krb5kdc failed to start. Check /var/log/ (syslog) for details." >&2
exit 1
fi
exec kadmind -nofork
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${KNOE_AUTH_NAME}
namespace: ${KNOE_AUTH_NAMESPACE}
spec:
replicas: 1
selector:
matchLabels:
app: ${KNOE_AUTH_NAME}
template:
metadata:
labels:
app: ${KNOE_AUTH_NAME}
spec:
${host_net_block}
${dns_policy_block}
containers:
- name: kdc
image: ${KNOE_AUTH_IMAGE}
imagePullPolicy: IfNotPresent
command: ["/bin/bash", "/opt/knoe-auth-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: knoe-auth-secrets
key: master_password
- name: PROLE_KDC_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: knoe-auth-secrets
key: admin_password
- name: PROLE_KDC_TRUST_SHARED_PASSWORD
valueFrom:
secretKeyRef:
name: knoe-auth-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: knoe-auth-secrets
key: trust_password
- name: PROLE_CHILD_REALM
value: "${PROLE_CHILD_REALM:-}"
- name: PROLE_CHILD_WORKGROUP
value: "${PROLE_CHILD_WORKGROUP:-}"
- name: PROLE_CHILD_NETBIOS_NAME
value: "${PROLE_CHILD_NETBIOS_NAME:-}"
- name: PROLE_CHILD_SERVER_STRING
value: "${PROLE_CHILD_SERVER_STRING:-}"
- name: PROLE_SAMBA_SERVER_ROLE
value: "${PROLE_SAMBA_SERVER_ROLE:-}"
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: knoe-auth-kdc-config
mountPath: /opt/knoe-auth-kdc
- name: knoe-auth-kdc-data
mountPath: /var/lib/krb5kdc
- name: knoe-auth-kdc-data
mountPath: /etc/krb5kdc
volumes:
- name: knoe-auth-kdc-config
configMap:
name: knoe-auth-kdc-config
- name: knoe-auth-kdc-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: ${KNOE_AUTH_SERVICE}
namespace: ${KNOE_AUTH_NAMESPACE}
spec:
selector:
app: ${KNOE_AUTH_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_knoe_auth_manifest
local rollout_timeout="$KNOE_AUTH_ROLLOUT_TIMEOUT"
if [[ "$deployment_present" -eq 0 ]]; then
rollout_timeout="$KNOE_AUTH_DEPLOY_TIMEOUT"
fi
if ! kubectl -n "$KNOE_AUTH_NAMESPACE" rollout status deploy/${KNOE_AUTH_NAME} --timeout="${rollout_timeout}s"; then
err "WARN: knoe-auth rollout did not complete within ${rollout_timeout}s. Collecting diagnostics..."
latest_pod=$(kubectl -n "$KNOE_AUTH_NAMESPACE" get pod -l "app=${KNOE_AUTH_NAME}" --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[-1].metadata.name}' 2>/dev/null || true)
if [[ -n "${latest_pod:-}" ]]; then
err "--- describe pod ${latest_pod} ---"
kubectl -n "$KNOE_AUTH_NAMESPACE" describe pod "$latest_pod" 1>&2 || true
err "--- last 200 log lines from ${latest_pod} ---"
kubectl -n "$KNOE_AUTH_NAMESPACE" logs "$latest_pod" --tail=200 1>&2 || true
else
err "[WARN] No pods found for app=${KNOE_AUTH_NAME} to collect logs from."
fi
if maybe_cleanup_stale_kdc "rollout timeout"; then
log "Re-applying knoe-auth after cleanup..."
apply_knoe_auth_manifest
kubectl -n "$KNOE_AUTH_NAMESPACE" rollout status deploy/${KNOE_AUTH_NAME} --timeout="${KNOE_AUTH_DEPLOY_TIMEOUT}s" || true
fi
fi
}
cleanup_knoe_auth() {
log "Removing knoe-auth resources (if present)..."
kubectl -n "$KNOE_AUTH_NAMESPACE" delete service "$KNOE_AUTH_SERVICE" --ignore-not-found
kubectl -n "$KNOE_AUTH_NAMESPACE" delete deployment "$KNOE_AUTH_NAME" --ignore-not-found
kubectl -n "$KNOE_AUTH_NAMESPACE" delete configmap knoe-auth-kdc-config --ignore-not-found
kubectl -n "$KNOE_AUTH_NAMESPACE" delete secret knoe-auth-secrets --ignore-not-found
}
status() {
log "--- init_knoe_auth status ---"
log "Namespace: $KNOE_AUTH_NAMESPACE"
log "knoe-auth enabled: ${KNOE_AUTH_ENABLED:-0}"
log "KDC realm: ${PROLE_KDC_REALM:-<unset>}"
log "knoe-auth service: ${KNOE_AUTH_SERVICE:-<unset>}"
log "knoe-auth image: ${KNOE_AUTH_IMAGE:-<unset>}"
if kubectl -n "$KNOE_AUTH_NAMESPACE" get deploy "$KNOE_AUTH_NAME" >/dev/null 2>&1; then
log "[OK] knoe-auth deployment present"
if maybe_cleanup_stale_kdc "status check" "strict"; then
log "[INFO] Stale knoe-auth deployment removed. Re-run init_knoe_auth.sh update to recreate."
fi
else
log "[INFO] knoe-auth deployment not present"
fi
}
case "$ACTION" in
initialize|init|update|deploy|start)
ensure_tools
ensure_namespace
ensure_knoe_auth
;;
status)
ensure_tools
status
;;
cleanup|delete|remove)
ensure_tools
ensure_namespace
cleanup_knoe_auth
;;
*)
err "Usage: $0 {initialize|update|status|cleanup}"
exit 2
;;
esac