Updated by fix-consistency on 2026-10-11: - workplan status: backlog → active Assistant: claude-code Assistant-Model: opus Assistant-Process: 1370019@bnt-lap001 Assistant-Session: d462dd63-16de-4189-ae70-b9cd6566bf87
18 KiB
| 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 | active | residual | worsch | netkingdom | 2026-05-20 | 2026-10-03 | 1075448f-d533-5f9e-94b7-c3adfe151a07 |
|
|
NK-WP-0011 — Enterprise Federation & SAML (Expanded-Mode Keycloak)
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:platformandtenant: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.mdandtools/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/backlogby founder-authorized triage — off the critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged; promote back when demand or risk appears. See the-custodianhistory/20261011-netkingdom-security-progress-assessment.md.