prole/infrastructure/playbooks/kerberos_trust_setup.yml
chrisfu bb71cf68ea feat(auth): dual IdP for db.prole.org — Google OAuth + Kerberos SPNEGO
knoe-auth (Spring Boot OIDC provider):
- AuthProperties: add google.workspaceDomain and kerberos.servicePrincipal fields
- GoogleOAuthService: validate hd (hosted domain) claim; restrict to configured workspace
- LoginController: /login/google endpoint + SPNEGO negotiation entry point
- PrincipalNormalizer: map Kerberos principal (user@REALM) to knoe-auth user
- application.yml: add spring.security.kerberos and oauth2.client stubs (values
  injected at runtime from env / Kubernetes Secrets)
- knoe-auth-deployment.yaml: mount HTTP keytab Secret; add GOOGLE_PROLE_CLIENT_ID /
  GOOGLE_PROLE_CLIENT_SECRET env from oauth2-proxy-prole-secret
- knoe-auth-http-keytab-secret.example.yaml: example Secret for HTTP/<host> keytab

Kong (init_kong.sh):
- Add db.prole.org route in k3s mode block via oauth2-proxy upstream
- Mode-gate: only registered for k3s, excluded for k3d/k8s

Supabase / oauth2-proxy:
- New supabase/helm/oauth2-proxy Helm chart: gates Supabase Studio at db.prole.org
  with Google OAuth (email-domain=prole.org) + cookie settings for .prole.org domain
- values-k3s.yaml: k3s-specific overrides (upstream service, TLS, cookie domain)
- secret-example.yaml: placeholder for oauth2-proxy-prole-secret

Ansible:
- infrastructure/playbooks/kerberos_trust_setup.yml: automates samba-tool domain
  trust create on myrddin.prole.org for PROLE.LOCAL ↔ PROLE.ORG cross-realm trust

Test:
- GoogleLoginProleOrgTest: verifies hd=prole.org tokens are accepted; hd=other.com rejected

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 20:03:09 -07:00

133 lines
5.3 KiB
YAML

---
# kerberos_trust_setup.yml — Register the reciprocal PROLE.LOCAL ↔ PROLE.ORG cross-realm trust
# in Samba AD on myrddin.prole.org.
#
# PREREQUISITES
# -------------
# 1. Run AFTER init_knoe_users.sh initialize completes on the k3s cluster.
# The trust_shared_password used here must match the value stored in the
# in-cluster Secret knoe-kdc-secrets (key: trust_shared_password). The
# in-cluster MIT KDC must already have created the principal
# krbtgt/PROLE.ORG@PROLE.LOCAL
# before this playbook runs.
#
# 2. trust_kdc_ip must be the ClusterIP of the 'auth' Service in the knoe-system
# namespace. This is a cluster-internal IP; myrddin (the Samba DC) must be
# reachable to it either because it is the k3s server node (and therefore on
# the pod/service CIDR network) or because a static route has been added.
# Resolve it at runtime with:
# kubectl -n knoe-system get svc auth -o jsonpath='{.spec.clusterIP}'
#
# DRY-RUN
# -------
# ansible-playbook infrastructure/playbooks/kerberos_trust_setup.yml \
# --check --diff \
# -e trust_shared_password=dummy \
# -e samba_admin_password=dummy
#
# FULL RUN
# --------
# export PROLE_TRUST_SHARED_PASSWORD=<secret>
# export SAMBA_ADMIN_PASSWORD=<secret>
# ansible-playbook infrastructure/playbooks/kerberos_trust_setup.yml \
# -e trust_kdc_ip=$(kubectl -n knoe-system get svc auth -o jsonpath='{.spec.clusterIP}')
- name: Register PROLE.LOCAL cross-realm trust in Samba AD on myrddin
hosts: myrddin.prole.org
gather_facts: false
become: true
vars:
trust_realm: "PROLE.LOCAL"
trust_kdc_ip: "" # override via --extra-vars or resolve at call site (see above)
trust_shared_password: "{{ lookup('env', 'PROLE_TRUST_SHARED_PASSWORD') }}"
samba_admin_password: "{{ lookup('env', 'SAMBA_ADMIN_PASSWORD') }}"
tasks:
# ------------------------------------------------------------------
# 0. Resolve the ClusterIP if the caller did not supply trust_kdc_ip
# ------------------------------------------------------------------
- name: Resolve trust_kdc_ip from cluster if not provided
ansible.builtin.command:
cmd: kubectl -n knoe-system get svc auth -o jsonpath='{.spec.clusterIP}'
delegate_to: localhost
become: false
register: _kdc_clusterip
when: trust_kdc_ip == ""
changed_when: false
- name: Set trust_kdc_ip fact from cluster lookup
ansible.builtin.set_fact:
trust_kdc_ip: "{{ _kdc_clusterip.stdout | trim }}"
when: trust_kdc_ip == "" and _kdc_clusterip is defined
- name: Assert trust_kdc_ip is set
ansible.builtin.assert:
that:
- trust_kdc_ip != ""
fail_msg: >
trust_kdc_ip is empty. Provide it via --extra-vars or ensure
'kubectl -n knoe-system get svc auth' succeeds from the control node.
# ------------------------------------------------------------------
# 1. Check if the trust already exists (idempotency guard)
# ------------------------------------------------------------------
- name: Check whether PROLE.LOCAL trust already exists in Samba
ansible.builtin.command:
cmd: samba-tool domain trust list
register: _trust_list
changed_when: false
failed_when: false
- name: Set fact — trust already present
ansible.builtin.set_fact:
_trust_exists: "{{ trust_realm in _trust_list.stdout }}"
# ------------------------------------------------------------------
# 2. Add PROLE.LOCAL realm block to /etc/krb5.conf on myrddin
# ------------------------------------------------------------------
- name: Ensure PROLE.LOCAL realm block is present in /etc/krb5.conf
ansible.builtin.blockinfile:
path: /etc/krb5.conf
marker: "# {mark} ANSIBLE MANAGED BLOCK — {{ trust_realm }}"
insertafter: '^\[realms\]'
block: |
{{ trust_realm }} = {
kdc = {{ trust_kdc_ip }}
admin_server = {{ trust_kdc_ip }}
}
when: not _trust_exists
# ------------------------------------------------------------------
# 3. Register the trust in Samba
# ------------------------------------------------------------------
- name: Create Kerberos cross-realm trust for PROLE.LOCAL in Samba AD
ansible.builtin.command:
cmd: >
samba-tool domain trust create {{ trust_realm }}
--type=external
--direction=both
--password={{ trust_shared_password }}
-U administrator%{{ samba_admin_password }}
no_log: true
register: _trust_create
changed_when: "'Successfully created trust' in _trust_create.stdout or _trust_create.rc == 0"
when: not _trust_exists
# ------------------------------------------------------------------
# 4. Validate the trust
# ------------------------------------------------------------------
- name: Validate the PROLE.LOCAL trust in Samba AD
ansible.builtin.command:
cmd: >
samba-tool domain trust validate {{ trust_realm }}
-U administrator%{{ samba_admin_password }}
no_log: true
register: _trust_validate
changed_when: false
failed_when: _trust_validate.rc != 0
- name: Print trust validation result
ansible.builtin.debug:
msg: "{{ _trust_validate.stdout_lines }}"