mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 12:03:59 +00:00
ansible: rewrite kerberos_trust_setup for MIT KDC trust
samba-tool domain trust create --type=external only works against
another writeable AD-style DC; against an MIT KDC it fails with
"Failed to find a writeable DC for domain 'KNOE.LOCAL'". Our peer at
svc/auth in knoe-system is a plain Kerberos KDC, so we cannot use that
path.
Replace the trust create/validate/show steps with the supported
Samba-AD <-> MIT-KDC approach: create the inter-realm TGT principal as
an ordinary user account in Samba whose sAMAccountName is
"krbtgt/KNOE.LOCAL", with its password synced to the cluster Secret
knoe-system/knoe-kdc-secrets/trust_shared_password (which the MIT side
already keys against). Steps:
1. samba-tool user list (idempotency probe)
2. samba-tool user create krbtgt/KNOE.LOCAL ... (when missing)
3. samba-tool user setpassword krbtgt/KNOE.LOCAL (when present, to
re-sync after a cluster Secret rotation)
4. samba-tool user setexpiry --noexpiry
5. ldbmodify msDS-SupportedEncryptionTypes=28 (RC4+AES128+AES256
to match what init_kdc.sh sets on the MIT side)
6. samba-tool user show (smoke probe)
7. debug task prints the manual kvno smoke-test command
Cluster-secret lookups and krb5.conf [realms]/[domain_realm] edits are
unchanged - those parts were correct.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
227f49042c
commit
555da4acfc
@ -1,12 +1,26 @@
|
||||
---
|
||||
# kerberos_trust_setup.yml — Register the reciprocal KNOE.LOCAL ↔ PROLE.ORG cross-realm trust
|
||||
# in Samba AD on myrddin.prole.org.
|
||||
# kerberos_trust_setup.yml — Register the KNOE.LOCAL ↔ PROLE.ORG cross-realm
|
||||
# Kerberos trust in Samba AD on myrddin.prole.org.
|
||||
#
|
||||
# This unblocks SSO from PROLE.ORG (the on-prem Samba AD realm) into KNOE.LOCAL
|
||||
# (the in-cluster MIT KDC realm), which is required for chrisfu@KNOE.LOCAL→
|
||||
# chrisfu@PROLE.ORG service ticket flows targeting db.prole.org and other
|
||||
# (the in-cluster MIT KDC realm), which is required for chrisfu@PROLE.ORG →
|
||||
# service@KNOE.LOCAL ticket flows targeting db.prole.org / pg_oauth and other
|
||||
# cluster-hosted services that authenticate against the KNOE.LOCAL KDC.
|
||||
#
|
||||
# Why not `samba-tool domain trust create`?
|
||||
# -----------------------------------------
|
||||
# That command requires the remote side to be another writeable AD-style DC,
|
||||
# and tries to discover it via DNS-SRV lookup. Our peer is the in-cluster MIT
|
||||
# KDC at svc/auth.knoe-system — a plain Kerberos KDC, not AD — so the
|
||||
# command bails with "Failed to find a writeable DC for domain KNOE.LOCAL".
|
||||
#
|
||||
# The supported Samba-AD ↔ MIT-KDC approach is to create the inter-realm TGT
|
||||
# principal as an ordinary user account in Samba whose sAMAccountName equals
|
||||
# `krbtgt/KNOE.LOCAL`, and to share that account's password with the MIT side.
|
||||
# The MIT side already has the matching principal (created by init_kdc.sh in
|
||||
# the knoe-db repo), keyed to the same trust_shared_password we pull from the
|
||||
# in-cluster Secret knoe-system/knoe-kdc-secrets.
|
||||
#
|
||||
# PREREQUISITES
|
||||
# -------------
|
||||
# 1. Run AFTER init_knoe_users.sh / init_kdc.sh has run on the k3s cluster.
|
||||
@ -134,25 +148,34 @@
|
||||
or set SAMBA_ADMIN_PASSWORD / -e samba_admin_password=...
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 1. Check if the trust already exists (idempotency guard)
|
||||
# 1. Idempotency probe — does the inter-realm krbtgt user exist?
|
||||
# ------------------------------------------------------------------
|
||||
- name: Check whether {{ trust_realm }} trust already exists in Samba
|
||||
# NOTE: `samba-tool domain trust create --type=external` only works
|
||||
# against another AD-style writeable DC. For an MIT KDC peer
|
||||
# (which KNOE.LOCAL is — it's the in-cluster Heimdal/MIT KDC, not AD),
|
||||
# the documented approach is to create the inter-realm TGT
|
||||
# principal as an ordinary user account in Samba and share its
|
||||
# password with the MIT KDC. The MIT side already has
|
||||
# krbtgt/KNOE.LOCAL@PROLE.ORG (created by init_kdc.sh) using the
|
||||
# same trust_shared_password we just fetched from the cluster Secret.
|
||||
- name: Check whether krbtgt/{{ trust_realm }} user already exists in Samba
|
||||
ansible.builtin.command:
|
||||
cmd: samba-tool domain trust list
|
||||
register: _trust_list
|
||||
cmd: >
|
||||
samba-tool user list
|
||||
register: _samba_users
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Set fact — trust already present
|
||||
- name: Set fact — inter-realm krbtgt user already present
|
||||
ansible.builtin.set_fact:
|
||||
_trust_exists: "{{ trust_realm in _trust_list.stdout }}"
|
||||
_trust_exists: "{{ ('krbtgt/' + trust_realm) in _samba_users.stdout }}"
|
||||
|
||||
- name: Report trust pre-existence
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ trust_realm }} trust
|
||||
{{ 'already present in Samba AD — skipping create.'
|
||||
krbtgt/{{ trust_realm }} user
|
||||
{{ 'already present in Samba — will reset password to match cluster Secret.'
|
||||
if _trust_exists else 'is missing — will create.' }}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
@ -179,60 +202,128 @@
|
||||
knoe.local = {{ trust_realm }}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 3. Register the trust in Samba
|
||||
# 3. Create the inter-realm krbtgt user in Samba (if missing)
|
||||
# ------------------------------------------------------------------
|
||||
- name: Create Kerberos cross-realm trust for {{ trust_realm }} in Samba AD
|
||||
# The account is named exactly `krbtgt/KNOE.LOCAL` — the slash is
|
||||
# legal in a Samba sAMAccountName/userPrincipalName. Samba's KDC
|
||||
# will then issue cross-realm TGTs whose source principal is
|
||||
# `krbtgt/KNOE.LOCAL@PROLE.ORG` (PROLE.ORG is the local realm,
|
||||
# added implicitly).
|
||||
#
|
||||
# The "no_log" wrapper protects the password but also hides the
|
||||
# error message on failure; if a real run dies here re-run by hand
|
||||
# to see stderr (see playbook header).
|
||||
- name: Create inter-realm krbtgt user krbtgt/{{ trust_realm }}
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
samba-tool domain trust create {{ trust_realm }}
|
||||
--type=external
|
||||
--direction=both
|
||||
--password={{ trust_shared_password }}
|
||||
-U administrator%{{ samba_admin_password }}
|
||||
argv:
|
||||
- samba-tool
|
||||
- user
|
||||
- create
|
||||
- "krbtgt/{{ trust_realm }}"
|
||||
- "{{ trust_shared_password }}"
|
||||
- "--description=Inter-realm TGT for {{ trust_realm }} (MIT KDC) cross-realm trust"
|
||||
- "--use-username-as-cn"
|
||||
- "-U"
|
||||
- "administrator%{{ samba_admin_password }}"
|
||||
no_log: true
|
||||
register: _trust_create
|
||||
changed_when: "'Successfully created trust' in (_trust_create.stdout | default('')) or _trust_create.rc == 0"
|
||||
register: _krbtgt_create
|
||||
changed_when: _krbtgt_create.rc == 0
|
||||
when: not _trust_exists
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 4. Validate the trust
|
||||
# 4. Reset the password (idempotent: handles both fresh create and
|
||||
# re-runs where the cluster Secret may have been rotated).
|
||||
# Skipped on the fresh-create path because step 3 already set it.
|
||||
# ------------------------------------------------------------------
|
||||
- name: Validate the {{ trust_realm }} trust in Samba AD
|
||||
- name: Re-sync krbtgt/{{ trust_realm }} password with cluster Secret
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
samba-tool domain trust validate {{ trust_realm }}
|
||||
-U administrator%{{ samba_admin_password }}
|
||||
argv:
|
||||
- samba-tool
|
||||
- user
|
||||
- setpassword
|
||||
- "krbtgt/{{ trust_realm }}"
|
||||
- "--newpassword={{ trust_shared_password }}"
|
||||
- "-U"
|
||||
- "administrator%{{ samba_admin_password }}"
|
||||
no_log: true
|
||||
register: _trust_validate
|
||||
register: _krbtgt_setpw
|
||||
changed_when: _krbtgt_setpw.rc == 0
|
||||
when: _trust_exists
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 5. Disable password expiry on the krbtgt account
|
||||
# ------------------------------------------------------------------
|
||||
- name: Disable password expiry on krbtgt/{{ trust_realm }}
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- samba-tool
|
||||
- user
|
||||
- setexpiry
|
||||
- "krbtgt/{{ trust_realm }}"
|
||||
- "--noexpiry"
|
||||
- "-U"
|
||||
- "administrator%{{ samba_admin_password }}"
|
||||
no_log: true
|
||||
register: _krbtgt_noexpiry
|
||||
changed_when: _krbtgt_noexpiry.rc == 0
|
||||
failed_when: _krbtgt_noexpiry.rc != 0
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 6. Force supported encryption types to AES128+AES256+RC4
|
||||
# msDS-SupportedEncryptionTypes = 28 = 0x04 (RC4) | 0x08 (AES128) | 0x10 (AES256)
|
||||
# This must match what the MIT KDC offers (init_kdc.sh defaults
|
||||
# to AES256 keys for cross-realm krbtgt principals).
|
||||
# ------------------------------------------------------------------
|
||||
- name: Set msDS-SupportedEncryptionTypes=28 on krbtgt/{{ trust_realm }}
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
set -euo pipefail
|
||||
ldif=$(mktemp)
|
||||
DN=$(samba-tool user show "krbtgt/{{ trust_realm }}" \
|
||||
-U "administrator%{{ samba_admin_password }}" \
|
||||
| awk -F': ' '/^dn:/ {print $2; exit}')
|
||||
if [ -z "$DN" ]; then
|
||||
echo "Could not resolve DN for krbtgt/{{ trust_realm }}" >&2
|
||||
exit 1
|
||||
fi
|
||||
cat > "$ldif" <<EOF
|
||||
dn: $DN
|
||||
changetype: modify
|
||||
replace: msDS-SupportedEncryptionTypes
|
||||
msDS-SupportedEncryptionTypes: 28
|
||||
EOF
|
||||
ldbmodify -H /var/lib/samba/private/sam.ldb "$ldif"
|
||||
rm -f "$ldif"
|
||||
no_log: true
|
||||
register: _krbtgt_enctype
|
||||
changed_when: "'Modified 1 records' in (_krbtgt_enctype.stdout | default(''))"
|
||||
failed_when: _krbtgt_enctype.rc != 0
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 7. Smoke probe — confirm the user is visible to samba-tool
|
||||
# ------------------------------------------------------------------
|
||||
- name: Smoke probe — samba-tool user show krbtgt/{{ trust_realm }}
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- samba-tool
|
||||
- user
|
||||
- show
|
||||
- "krbtgt/{{ trust_realm }}"
|
||||
- "-U"
|
||||
- "administrator%{{ samba_admin_password }}"
|
||||
no_log: true
|
||||
register: _krbtgt_show
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
# In --check mode the create step is skipped, so a missing trust
|
||||
# is expected and shouldn't fail the dry run. In a real run we
|
||||
# always want a non-zero rc to fail.
|
||||
failed_when:
|
||||
- _trust_validate.rc != 0
|
||||
- not (ansible_check_mode and not _trust_exists)
|
||||
failed_when: _krbtgt_show.rc != 0
|
||||
|
||||
- name: Print trust validation result
|
||||
- name: Print summary
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ _trust_validate.stdout_lines }}"
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 5. Smoke test — fetch a cross-realm TGT
|
||||
# ------------------------------------------------------------------
|
||||
- name: Smoke test — list krbtgt principals seen by Samba KDC
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
samba-tool domain trust show {{ trust_realm }}
|
||||
-U administrator%{{ samba_admin_password }}
|
||||
no_log: true
|
||||
register: _trust_show
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
failed_when:
|
||||
- _trust_show.rc != 0
|
||||
- not (ansible_check_mode and not _trust_exists)
|
||||
|
||||
- name: Print trust show output
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ _trust_show.stdout_lines }}"
|
||||
msg:
|
||||
- "krbtgt/{{ trust_realm }} present in Samba (PROLE.ORG realm)."
|
||||
- "Password is now in sync with knoe-system/knoe-kdc-secrets/trust_shared_password."
|
||||
- "msDS-SupportedEncryptionTypes set to 28 (RC4 + AES128 + AES256)."
|
||||
- "From a PROLE.ORG client try:"
|
||||
- " kdestroy && kinit chrisfu@PROLE.ORG"
|
||||
- " kvno HTTP/auth.knoe.dev@{{ trust_realm }}"
|
||||
- " klist # expect krbtgt/{{ trust_realm }}@PROLE.ORG"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user