apiVersion: v1 kind: ConfigMap metadata: name: knoe-kdc-config namespace: knoe-system data: krb5.conf: | [libdefaults] # AES-only: RC4 (arcfour-hmac) hard-removed from JDK 21, not supported by # the service account (msDS-SupportedEncryptionTypes=24 = AES128+AES256). # Note: if cross-realm trust (KNOE.LOCAL ↔ PROLE.ORG) is implemented via # the KDC sidecar, these will need to include arcfour-hmac for krbtgt # principals (RC4 avoids the MIT/Samba salt mismatch). See entrypoint.sh. permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 default_realm = KNOE.LOCAL dns_lookup_realm = false dns_lookup_kdc = false [realms] KNOE.LOCAL = { kdc = 127.0.0.1 admin_server = 127.0.0.1 } PROLE.ORG = { kdc = 10.0.0.3 admin_server = 10.0.0.3 } [capaths] KNOE.LOCAL = { PROLE.ORG = . } PROLE.ORG = { KNOE.LOCAL = . } kdc.conf: | [kdcdefaults] kdc_ports = 88 kdc_tcp_ports = 88 [realms] KNOE.LOCAL = { 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/admin@KNOE.LOCAL * entrypoint.sh: | #!/usr/bin/env bash set -euo pipefail # Enable verbose debug if requested if [[ "${KNOE_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 KNOE.LOCAL" | 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-kdc/krb5.conf ]]; then cp /opt/knoe-kdc/krb5.conf /etc/krb5.conf fi if [[ -f /opt/knoe-kdc/kdc.conf ]]; then cp /opt/knoe-kdc/kdc.conf /etc/krb5kdc/kdc.conf fi if [[ -f /opt/knoe-kdc/kadm5.acl ]]; then cp /opt/knoe-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-kdc-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-kdc-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}}" # ------------------------------------------------------------------ # Cross-realm krbtgt principals — RC4 only. # # Both directions of the trust live as their own krbtgt principal, # each keyed to the same shared password. We pin RC4 (arcfour-hmac) # because AES key derivation requires a salt, and Samba's salt # convention ( + UPN) does not match MIT's # ( + ). RC4 derives keys from # the password alone, so both sides converge with no salt fight. # # NOTE: if this path is activated, also re-add arcfour-hmac to # permitted_enctypes in krb5.conf so the KDC can issue RC4 tickets. # ------------------------------------------------------------------ # Outbound: KNOE.LOCAL → PROLE.ORG (issued here, decrypted by Samba) if ! kadmin.local -q "get_principal krbtgt/${PROLE_KDC_TRUST_REALM}@${PROLE_KDC_REALM}" >/dev/null 2>&1; then echo "Creating outbound trust principal krbtgt/${PROLE_KDC_TRUST_REALM}@${PROLE_KDC_REALM}..." kadmin.local -q "addprinc -pw ${shared_pw} -e arcfour-hmac:normal krbtgt/${PROLE_KDC_TRUST_REALM}@${PROLE_KDC_REALM}" fi # Inbound: PROLE.ORG → KNOE.LOCAL (issued by Samba, decrypted here) if ! kadmin.local -q "get_principal krbtgt/${PROLE_KDC_REALM}@${PROLE_KDC_TRUST_REALM}" >/dev/null 2>&1; then echo "Creating inbound trust principal krbtgt/${PROLE_KDC_REALM}@${PROLE_KDC_TRUST_REALM}..." kadmin.local -q "addprinc -pw ${shared_pw} -e arcfour-hmac:normal krbtgt/${PROLE_KDC_REALM}@${PROLE_KDC_TRUST_REALM}" fi # NOTE: The Samba-side trust account (user "krbtgt_${PROLE_KDC_REALM}" # in PROLE.ORG with UPN/SPN krbtgt/${PROLE_KDC_REALM}) is provisioned # OUT-OF-BAND by this repo's Ansible playbook: # infrastructure/playbooks/kerberos_trust_setup.yml # Earlier versions of this script tried to use a remote "kadmin" # client to write that principal into Samba, but Samba AD does not # accept additions over MIT's kadmin protocol — it always failed # with "Missing parameters in krb5.conf required for kadmin client". # Run the playbook once after this KDC comes up: # ANSIBLE_VAULT_PASSWORD_FILE=$PWD/.vault_pass \ # ansible-playbook infrastructure/playbooks/kerberos_trust_setup.yml echo "Note: Samba-side trust account is provisioned out-of-band by" echo " infrastructure/playbooks/kerberos_trust_setup.yml" 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