net-kingdom/workplans/NK-WP-0011-enterprise-federation-saml.md
tegwick 53f8327cdb
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
NK-WP-0011: set status blocked (sync had reverted backlog to active)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 308701@bnt-lap001
Assistant-Session: 5548e447-444c-4dcc-bed1-05c16eebfe56
2026-10-28 09:24:17 +01:00

18 KiB
Raw Blame History

id type title domain repo status flavor owner topic_slug created updated state_hub_workstream_id depends_on supersedes_tasks
NK-WP-0011 workplan Enterprise Federation & SAML — Expanded-Mode Keycloak Identity Broker infotech net-kingdom blocked residual worsch netkingdom 2026-05-20 2026-10-28 1075448f-d533-5f9e-94b7-c3adfe151a07
NK-WP-0003
NK-WP-0004
NK-WP-0006
NK-WP-0001-T05
NK-WP-0001-T06
NK-WP-0001-T07
NK-WP-0001-T08

NK-WP-0011 — Enterprise Federation & SAML (Expanded-Mode Keycloak)

Blocked 2026-10-28 (founder triage): every task waits on the ADR-0009 adoption trigger (a named enterprise-IdP/tenant need); SCOPE.md lists enterprise federation (C5) as backlog. Return to active when the trigger occurs.

Extracted from NK-WP-0001 (T05–T08, the deferred Keycloak path) and refined against where net-kingdom actually stands today: a deployed KeyCape lightweight stack, an OpenBao runtime-secret authority, and a recursive platform/tenant authorization model. This is expanded identity mode in the architecture (docs/platform-identity-security-architecture.md).

Goal

Stand up Keycloak as an identity broker that federates upstream enterprise identity providers (Microsoft Entra ID / Azure AD via OIDC, on-prem Active Directory via LDAP, and generic SAML 2.0 IdPs) and issues NetKingdom IAM Profile-conformant tokens downstream — without displacing flex-auth as the authorization decision point or breaking the recursive platform/tenant boundary.

This is the answer to the long-standing open question "when does the platform switch from key-cape lightweight mode to Keycloak expanded mode?" — expanded mode exists specifically to onboard identities that originate in an external enterprise IdP, which the lightweight Authelia + LLDAP stack cannot broker.

Why this is not just "resume NK-WP-0001"

NK-WP-0001 assumed a greenfield: bootstrap Vault, build PostgreSQL, treat Keycloak as the internal user store. None of those assumptions hold now:

NK-WP-0001 assumption Current reality Effect on this plan
HashiCorp Vault, bootstrapped from KeePassXC OpenBao is the runtime secret authority (NK-WP-0006); SOPS/age + agent bootstrap exist (NK-WP-0004/0005) Keycloak DB + admin secrets come from OpenBao via ESO; no new vault bootstrap
PostgreSQL built from scratch CloudNativePG running on RAILIANCE01 (NK-WP-0003) Admit a database consumer through current platform owners; prove backup/restore
Keycloak is the internal source of truth (D2 hybrid) KeyCape lightweight stack is the deployed IAM Profile issuer Keycloak is a broker/federation front-end, not the primary user store
Authorization via Keycloak Authorization Services flex-auth + Topaz is the canonical PDP (ADR-0006) Keycloak AuthZ Services is at most an optional adapter, never canonical
Single-tenant Coulomb deployment Recursive tenant:platform vs tenant:coulomb model (NK-WP-0006) Evaluate realm-per-tenant; tenant admins must not receive platform-root
MFA solely via privacyIDEA provider JAR privacyIDEA deployed and upstream IdPs carry their own MFA MFA assurance source becomes a decision, not a default

Architecture

        Enterprise IdPs (upstream)
   Entra ID (OIDC)   AD (LDAP)   SAML 2.0 IdP
        │              │              │
        └──────────────┼──────────────┘
                       ▼
                 [ Keycloak ]  expanded-mode broker
                       │   realm-per-tenant candidate; IAM Profile issuer
                       │   secrets ← OpenBao (ESO)
                       │   MFA ← privacyIDEA *or* upstream assurance
                       ▼
        NetKingdom IAM Profile token (OIDC/PKCE)
                       │
                       ├──► applications (depend on the Profile, not the provider)
                       └──► flex-auth / Topaz  ── authorization decision (PDP)

   coexists with: KeyCape lightweight issuer (kc.coulomb.social)

Keycloak answers identity (who, how authenticated, coarse claims, assurance). It does not answer resource authorization — that stays in flex-auth (ADR-0006). It does not store runtime secrets — those stay in OpenBao.

Scope

In scope:

  • decision record for expanded-mode adoption: trigger, federation topology (broker vs SAML SP), realm isolation model, and coexistence with the KeyCape lightweight issuer
  • owner-packaged Keycloak image (privacyIDEA provider JAR only if selected and verified compatible) and managed deployment on railiance01
  • upstream federation: Entra ID (OIDC), AD (LDAP), generic SAML 2.0 IdP
  • claim mapping to the NetKingdom IAM Profile (issuer, audience, subject, groups, tenant, assurance evidence) and IAM Profile conformance checks
  • MFA / assurance source decision and enforcement of step-up for privileged actions
  • recursive tenancy: realm-per-tenant, platform-root guardrails, and the flex-auth/Topaz authorization boundary
  • backups, DR, break-glass, monitoring, and audit shipping for the broker

Out of scope:

  • replacing flex-auth/Topaz with Keycloak Authorization Services
  • migrating the deployed lightweight stack off KeyCape (coexistence only)
  • application-side OIDC client code (apps target the IAM Profile spec)
  • deploying OpenBao itself (Railiance platform) — consumed, not built
  • tenant-specific federation policy for tenants beyond tenant:platform and tenant:coulomb

Decide federation adoption and topology

id: NK-WP-0011-T01
state_hub_task_id: "a5807808-fb34-50de-8f67-9128011833d4"
status: done
priority: high

Decision record — expanded-mode adoption & federation topology. Write an ADR (ADR-0009) capturing: the concrete trigger for switching a tenant from lightweight to expanded mode; whether Keycloak acts as an OIDC identity broker, a SAML service provider, or both; the realm-per-tenant candidate and its alternatives mapped onto tenant:platform / tenant:coulomb; how the Keycloak issuer coexists with the KeyCape issuer (kc.coulomb.social) so applications still target one IAM Profile contract; and the canonical hostname/issuer for the broker. Resolve or supersede D2 from NK-WP-0001.

Admit the database consumer

id: NK-WP-0011-T02
state_hub_task_id: "2fe6f100-3a5d-563e-b033-7d7b846ae487"
status: wait
priority: high
blocking_reason: "ADR-0009 adoption trigger absent; then railiance-platform/rapp-postgres must admit the database consumer and return backup/restore evidence."
needs_human: true
decision_id: 8a5d1eb8-b665-4d25-9742-a15ecfc87c0c

PostgreSQL keycloak_db on the existing operator. Have railiance-platform and rapp-postgres admit a named Keycloak database consumer against the current database catalog and isolation needs. Do not assume the historical NK-WP-0003 instance is the correct placement. Source credentials from OpenBao via ESO into a K8s Secret. Confirm the existing backup schedule covers the new database and run a restore drill for keycloak_db specifically.

Package the broker deployment

id: NK-WP-0011-T03
state_hub_task_id: "32d1411b-10a4-5a8b-8f43-99ac46d83908"
status: wait
priority: high
blocking_reason: "ADR-0009 adoption trigger and named package/runtime owner absent; requires T02 database admission and governed OpenBao/ESO role plus immutable issuer assignment."
depends_on:
  - NK-WP-0011-T02

Deploy expanded-mode Keycloak. Build a custom image (kc.sh build, privacyIDEA provider JAR included only if T5 delegates MFA to privacyIDEA). Assign the package/runtime owner under ADR-0015 and deploy through its managed declaration on railiance01 behind Traefik + cert-manager at the issuer hostname from T1. Admin bootstrap secret and DB secret come from OpenBao/ESO — never typed, never in git. Hostname strictness + proxy headers configured for Traefik. Realm import is GitOps-friendly (realm JSON/CR in git).

Integrate an upstream identity provider

id: NK-WP-0011-T04
state_hub_task_id: "6697a994-7343-5ea8-8b37-bc3b921e5a9b"
status: wait
priority: high
blocking_reason: "Named tenant/upstream IdP owner/federation need absent; requires admitted broker and owner-reviewed tenant-scoped claim mappings plus actual login evidence."
depends_on:
  - NK-WP-0011-T03

Upstream federation. Configure identity brokering for Entra ID (OIDC), on-prem AD (LDAP user federation), and a generic SAML 2.0 IdP. Map each source's claims/attributes into the NetKingdom IAM Profile shape: issuer, audience, subject, groups, tenant, and assurance evidence. Define the attribute/claim mappers and group→role mapping. Verify a federated login end-to-end for at least the Entra ID path.

Define federated assurance

id: NK-WP-0011-T05
state_hub_task_id: "d845380d-3dbc-5e59-8f2b-5a4d1b32d89d"
status: wait
priority: medium
blocking_reason: "Adoption trigger absent; requires per-IdP assurance trust mapping and reviewed privileged step-up delivery from issuer/package and access-engine owners."
depends_on:
  - NK-WP-0011-T04

MFA / assurance source. Decide and implement the assurance model: MFA enforced by privacyIDEA (via the Keycloak provider JAR + a "privacyIDEA Browser" flow, carried over from NK-WP-0001) versus trusting upstream IdP MFA (e.g. Entra Conditional Access) and reflecting it as assurance evidence in the token. Require step-up for admin console and platform-root-sensitive clients. Ensure assurance evidence is carried in the IAM Profile token so flex-auth can gate privileged actions on it.

Verify IAM conformance and coexistence

id: NK-WP-0011-T06
state_hub_task_id: "9cb7fd93-c16e-5102-83ce-195b3aa87446"
status: wait
priority: high
blocking_reason: "Requires admitted live broker, canonical tenant issuer selection and dedicated test-client conformance/coexistence evidence; adoption trigger absent."
depends_on:
  - NK-WP-0011-T03
  - NK-WP-0011-T04
  - NK-WP-0011-T05

IAM Profile conformance & downstream coexistence. Run IAM Profile conformance checks against the Keycloak issuer (discovery document, PKCE, token/claim shape, JWKS, userinfo). Verify an application configured for the IAM Profile can authenticate against either the KeyCape or the Keycloak issuer per the T1 selection rule. Use the canonical canon/standards/iam-profile_v0.3.md contract and the executable suite in tools/iam-profile-conformance/. Document per-tenant issuer selection.

Enforce tenant and platform boundaries

id: NK-WP-0011-T07
state_hub_task_id: "38998c68-29bf-50d2-8c8d-0c75184d5833"
status: wait
priority: high
blocking_reason: "Requires tenant-engine tier/issuer ownership and access-engine boundary/freshness enforcement evidence after adoption trigger and broker admission."
depends_on:
  - NK-WP-0011-T03
  - NK-WP-0011-T04
  - NK-WP-0011-T05

Recursive tenancy & authorization boundary. Implement T1's reviewed realm/tenant topology with platform-root guardrails. If realm-per-tenant is selected, tenant admins manage only their realm; in every topology they must not be able to alter IAM Profile semantics, the platform realm, federation trust, OpenBao platform mounts, or audit retention (per the flex-auth/Topaz implications in the architecture doc). Confirm flex-auth + Topaz remains the PDP; if a Keycloak Authorization Services adapter is used at all, document it as a delegated, non-canonical adapter.

Prove recovery and audit delivery

id: NK-WP-0011-T08
state_hub_task_id: "e5f44ddc-9645-5f61-b84c-da5ab9cccb6d"
status: wait
priority: medium
blocking_reason: "Requires admitted database/broker, named recovery and audit owners, off-host restore and observed audit/break-glass receipts; adoption trigger absent."
depends_on:
  - NK-WP-0011-T02
  - NK-WP-0011-T03

Backups, DR, break-glass, monitoring, audit. Only sanitized declarative realm configuration belongs in git; keep credential-bearing exports in protected backup custody; DB backup + restore drill (T2); break-glass admin path disabled-by-default with alerting on use; Prometheus/Grafana for auth success/failure, MFA latency, federation errors. Ship Keycloak events to the durable platform audit sink alongside flex-auth/Topaz/OpenBao records, with correlation ids — satisfying the "Audit sink" and "Break-glass" rows of the production-readiness checklist.

Prove the isolation upgrade path

id: NK-WP-0011-T09
status: wait
priority: medium
state_hub_task_id: "d9dc4292-6b66-5797-9ff9-a1a4a556278e"
blocking_reason: "Requires named tenant and admitted package owner, canonical tier contract and isolated subject/issuer-preserving upgrade/rollback drill; adoption trigger absent."
depends_on:
  - NK-WP-0011-T03
  - NK-WP-0011-T07
  - NK-WP-0011-T08

Shared-realm to dedicated-instance upgrade (ADR-0009, decision 3). Write the owner-executed upgrade runbook and rehearse it in an isolated environment before any paid tier is offered. The drill must show issuer URL unchanged, every user sub and federated link preserved, login working after cutover, rollback by re-routing during the retention window, and per-tier backup and restore evidence. Coordinate with tenant-engine on deriving the tier from the IAM capability role; do not add an independent tier field.

Acceptance Criteria

  • A rehearsed shared-to-dedicated isolation upgrade preserves issuer and subjects.
  • An ADR records the expanded-mode trigger, federation topology, selected realm/tenant isolation model, and KeyCape/Keycloak issuer coexistence.
  • A federated user from at least one enterprise IdP (Entra ID) can log in and receive an IAM Profile-conformant token with tenant + assurance claims.
  • Keycloak secrets originate from OpenBao; none are bootstrapped from KeePassXC or committed to git.
  • flex-auth + Topaz remains the authorization decision point; Keycloak is not the canonical policy engine.
  • Tenant admins cannot cross the platform-root boundary.
  • Keycloak audit events land in the durable platform audit sink with correlation ids, and a DR/break-glass drill has passed.

Open Questions / Dependencies on Other Repos

  • key-cape: does coexistence require KeyCape changes, or can both issuers serve the same IAM Profile unchanged? (EP-NK-001 federation extension point.)
  • flex-auth: confirmed claim/decision-envelope contract for tenant + assurance evidence sourced from a federated token.
  • railiance-platform: OpenBao must expose a Keycloak auth role / ESO path before T3; unseal/break-glass story must be ready.
  • IAM Profile spec: resolved by NK-WP-0012. T6 consumes canon/standards/iam-profile_v0.3.md and tools/iam-profile-conformance/.

Infrastructure review — 2026-09-28

Keep in backlog until a named enterprise tenant, upstream IdP owner and concrete federation need justify operating another issuer. No Keycloak Deployment appears in today's cluster inventory. Realm-per-tenant remains a proposal to evaluate in T01, not a requirement derived from current topology; prove its mapping to tenant-engine's canonical identity/lifecycle contract.

The live issuer is https://kc.coulomb.social; IAM v0.3 is accepted and v0.4 step-up is proposed. T01/T05/T06 must coordinate with NK-WP-0042 and preserve existing issuer/subject account bindings, audiences and session/revocation behavior. Do not infer equivalent assurance from an upstream MFA claim without a reviewed trust mapping. The single-node cluster and single-instance database providers offer no automatic HA guarantee. T02/T08 must name backup ownership, off-host custody and an isolated restore proof. OpenBao access is private via the platform operator path. Resource placement, packaging and runtime execution belong to their owners, not this canon repository.

Evidence and cross-plan priorities: estate review.

Dependency reconciliation — 2026-10-03

Accepted ADR-0009 decision1 prohibits starting T02–T09 without the named tenant, upstream IdP owner and concrete unmet federation need. None is recorded in this plan. Corrected active/todo to blocked/wait; T01 remains done. Local preparation is complete in expanded-mode admission requirements: owner deliverables, evidence gates, conformance limits and explicit resume criteria. New federation owner task IDs await trigger and owner acceptance; no deployment or issuer selection is implied by this packet.

Machine-readable wait reconciliation — 2026-10-03

T02 is the adoption admission root: owner/sponsor Bernd Worsch must confirm all three accepted ADR-0009 triggers from real demand. The pending hub decision 8a5d1eb8-b665-4d25-9742-a15ecfc87c0c records that demand is currently absent; it neither asks an agent to create demand nor grants a broker deployment. T02 also retains the subsequent database-owner admission and backup/restore requirements. Once the trigger exists, record actual owner task IDs before routing implementation.

T03–T09 now encode their concrete predecessor deliverables in depends_on. Every path reaches T02; no terminal historical infrastructure plan substitutes for adoption. Existing per-task owner commitments/evidence remain in the blocking reasons and admission requirements document. A deferred/declined admission decision requires a deliberate retain/cancel review, not automatic resume. All eight tasks remain wait; the workplan remains blocked.

Knowledge receipt: emergent-security 0.2.6 / start / verified-files / orientation-only; digest 8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02.

2026-10-11: demoted to flavor: residual / backlog by founder-authorized triage — off the critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged; promote back when demand or risk appears. See the-custodian history/20261011-netkingdom-security-progress-assessment.md.