These workplans exist only in the retired local hub. Their random pre-ADR-007 identifiers are refused by C-06 as stale references, so they cannot be registered. Deriving from the canonical record id takes no identity from anything: central does not hold them and the old ids die with the cache. Records central already holds were deliberately left untouched. Refs CUST-WP-0068-T06 Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
313 lines
15 KiB
Markdown
313 lines
15 KiB
Markdown
---
|
|
id: NK-WP-0023
|
|
type: workplan
|
|
title: "Integrate and deploy the user-engine onboarding portal"
|
|
domain: infotech
|
|
repo: net-kingdom
|
|
status: finished
|
|
owner: codex
|
|
topic_slug: netkingdom
|
|
created: "2026-07-27"
|
|
updated: "2026-07-30"
|
|
depends_on:
|
|
- USER-WP-0020
|
|
- KEY-WP-0004
|
|
state_hub_workstream_id: "fdb3deee-06c3-5d12-91ce-9c50b2ac0618"
|
|
---
|
|
|
|
# NK-WP-0023 - user-engine portal platform integration
|
|
|
|
Provide the NetKingdom-owned adapters and production integration required by
|
|
`USER-WP-0020`, using the Binky tenant-admin onboarding from `KEY-WP-0004-T02`
|
|
as the first acceptance case.
|
|
|
|
## T01 - Define source-of-truth and provisioning contracts
|
|
|
|
```task
|
|
id: NK-WP-0023-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "05d69347-ec34-59b7-a107-80db015ef0e6"
|
|
```
|
|
|
|
Ratify lifecycle sequencing and compensation across user-engine, LLDAP,
|
|
KeyCape, privacyIDEA, flex-auth, email verification, audit, and outbox
|
|
delivery. user-engine owns user-domain and membership intent; NetKingdom IAM
|
|
owns credentials, authentication factors, coarse authentication claims, and
|
|
provider subjects. Define externally-provisioned/federated ownership metadata
|
|
now so later enterprise directories do not require a domain rewrite.
|
|
|
|
## T02 - Implement the NetKingdom identity provisioning adapter
|
|
|
|
```task
|
|
id: NK-WP-0023-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "22113719-905b-54df-9ecb-0a0c456e0d35"
|
|
```
|
|
|
|
Implement idempotent create/link/suspend/reactivate/deprovision operations for
|
|
the lightweight LLDAP + privacyIDEA stack behind user-engine's
|
|
`IdentityProvisioningPort`. Use scoped service identity and approved secret
|
|
transport. Never expose directory admin credentials to the browser or
|
|
user-engine domain. Add reconciliation, retry, compensation, and drift
|
|
reporting rather than assuming a distributed transaction.
|
|
|
|
2026-07-28 implementation evidence: `identity-provisioner` now implements the
|
|
provider-neutral lifecycle API over LLDAP and runs as a non-root, internal-only
|
|
service in `sso`. Its directory credential remains confined to that pod;
|
|
user-engine receives only a namespace-local bearer token. NetworkPolicy allows
|
|
only user-engine to call it and only LLDAP/DNS egress. A live create/replay/delete
|
|
conformance run returned `resumed: false`, then `resumed: true`, and removed the
|
|
disposable subject. Reconciliation, compensation, and drift reporting remain.
|
|
|
|
2026-07-29 completion: image `identity-provisioner:12cdef5` adds read-only
|
|
drift inspection, active convergence of adapter-owned tenant groups and
|
|
suspension state, replay-safe deprovisioning, and best-effort compensation
|
|
when initial group projection fails. User-engine exposes these operations
|
|
through its provider-neutral port and retries one transient failure only under
|
|
the mandatory idempotency key. A disposable live probe proved clean initial
|
|
state, detected induced suspension drift, reported both the unexpected group
|
|
and status mismatch, removed the drift, returned to `in_sync`, deprovisioned,
|
|
and accepted the repeated deletion. The probe identity was removed.
|
|
|
|
## T03 - Integrate KeyCape login, claims, and MFA handoffs
|
|
|
|
```task
|
|
id: NK-WP-0023-T03
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "5721c5f9-6161-522c-a439-95f2613b5460"
|
|
```
|
|
|
|
Register the portal OIDC client with authorization code + PKCE, configure
|
|
callback/logout routes, verify issuer/audience/tenant/assurance claims, and
|
|
provide safe password and MFA enrollment/recovery handoffs. Preserve
|
|
platform-root separation and ensure tenant administration never implies
|
|
platform authority.
|
|
|
|
2026-07-27 implementation evidence: `user-engine-portal` is registered as a
|
|
public static KeyCape client with an exact callback and S256 PKCE. The portal
|
|
is live at `https://users.92-205-62-239.nip.io`, has a trusted ACME
|
|
certificate, begins the KeyCape/Authelia flow, and rejects an unregistered
|
|
callback. KeyCape image `key-cape:e8b4ede` maps an unambiguous
|
|
`tenant:<kind>:<slug>:users|admins` directory group envelope into the tenant
|
|
and coarse tenant-admin claims while refusing ambiguous multi-tenant mapping.
|
|
|
|
2026-07-28 update: KeyCape image `key-cape:909bb32` fails closed for directory
|
|
subjects in `netkingdom-suspended`: authorization-code exchange consumes the
|
|
code and returns a safety rejection, while `/userinfo` rejects previously
|
|
issued tokens. Unit and profile suites pass. Live Binky MFA acceptance remains.
|
|
|
|
2026-07-28 password-handoff evidence: NetKingdom now serves a short-lived,
|
|
single-use password setup form at the canonical KeyCape host. The portal
|
|
receives only an opaque HTTPS handoff URL and offers both initial creation and
|
|
renewal for linked identities; it never handles or stores the password. A live
|
|
disposable-user run proved prior-link revocation (400), current-link rendering
|
|
(200), non-consuming validation failure (400 then 200), successful OPAQUE
|
|
password registration and LLDAP login (200), replay denial (400), and cleanup.
|
|
The helper image is digest-pinned and the service is non-root, read-only, and
|
|
NetworkPolicy restricted. Binky's user-chosen password and MFA acceptance
|
|
remain.
|
|
|
|
2026-07-29 correction: live platform-root access exposed that the established
|
|
`net-kingdom-admins` bootstrap group was not mapped into the newer IAM
|
|
envelope. KeyCape `90a2078` now maps that group explicitly to
|
|
`tenant:platform` plus `platform-operator`, with regression coverage, while
|
|
tenant-admin mappings remain tenant scoped. The fixed image is Ready on
|
|
railiance01.
|
|
|
|
The subsequent live MFA callback exposed a missing destination-side
|
|
NetworkPolicy: user-engine allowed egress to KeyCape, but the SSO default deny
|
|
had no matching ingress. Commit `8e7229a` adds the namespace-and-pod-scoped
|
|
`:8080` rule plus verifier coverage. After applying it, an in-pod discovery
|
|
request from user-engine to KeyCape returns HTTP 200.
|
|
|
|
2026-07-29 complete: the live Binky browser flow verified the canonical
|
|
issuer/audience, Binky-only tenant/groups, tenant-admin role, AAL2
|
|
password-plus-OTP assurance, and denial of platform/Coulomb administration.
|
|
Password and MFA handoffs remain on NetKingdom-owned surfaces.
|
|
|
|
The live journey also exposed uid-only first-factor input. Authelia now uses
|
|
its documented LLDAP filter accepting either `uid` or `mail` while continuing
|
|
to resolve the stable uid identity. The updated ConfigMap passed server-side
|
|
validation and the restarted deployment is Ready without configuration
|
|
errors, so future users may enter either `bernd.worsch` or the full email.
|
|
|
|
## T04 - Integrate authorization, email, audit, and events
|
|
|
|
```task
|
|
id: NK-WP-0023-T04
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "efad8829-5d75-5ea1-9564-1618b1846525"
|
|
```
|
|
|
|
Define and implement flex-auth resources/actions for self, tenant-admin, and
|
|
platform-admin operations; route verification/invitation email without making
|
|
mailbox ownership an authorization fact; correlate user-engine, IAM,
|
|
authorization, and platform audit records; and connect durable outbox
|
|
delivery with replay and dead-letter evidence.
|
|
|
|
## T05 - Deploy on reef-railiance
|
|
|
|
```task
|
|
id: NK-WP-0023-T05
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "0c454447-c14f-586b-835b-4f00d43943d0"
|
|
```
|
|
|
|
Package the portal as a managed platform workload on the default
|
|
`rail-kubernetes` path on `reef-railiance`, with Postgres, OpenBao-backed
|
|
runtime references, NetworkPolicies, TLS ingress, backups, observability,
|
|
resource limits, rollout/rollback, and availability evidence. Do not place
|
|
this stateful platform control surface on scale-to-zero Knative.
|
|
|
|
Implementation evidence (2026-07-27): the internal-only portal foundation is
|
|
running on `reef-railiance` as `Deployment/user-engine` with dedicated healthy
|
|
`Cluster/user-engine-pg`, default-deny NetworkPolicies, immutable directly
|
|
imported image `user-engine:portal-c27012a`, and successful `/readyz` probes.
|
|
Public ingress remains intentionally absent until T03 supplies the verified
|
|
KeyCape OIDC edge. Forgejo OCI publication is pending restoration of the
|
|
OpenBao package-publisher capability; no credential was bypassed or exposed.
|
|
|
|
2026-07-28 update: public TLS ingress and KeyCape OIDC are active. The current
|
|
`user-engine:portal-e23674d` deployment is healthy with the dedicated CNPG
|
|
cluster, and the companion `identity-provisioner:dbf7cfd` deployment is
|
|
healthy behind namespace-scoped credentials and default-deny policy. Registry
|
|
publication, backup/restore evidence, metrics, and automated rollback remain.
|
|
|
|
2026-07-29 operability increment: deployed protected Prometheus metrics in
|
|
`user-engine:portal-2bcda7f`; an unmarked request is denied with 403 while the
|
|
trusted workload marker receives readiness plus 18 aggregate record series
|
|
without identity values. Added a daily atomic `pg_dump` schedule using the
|
|
existing CNPG application Secret, a restricted backup PVC, checksum/catalog
|
|
validation, and seven-day retention. The isolated restore drill verified the
|
|
latest archive in an ephemeral PostgreSQL instance with four public tables and
|
|
one migration row. `verify-operability.sh --exercise-rollback` rolled back to
|
|
`portal-746bf21`, verified readiness, and restored the declared image.
|
|
Machine-readable evidence is in
|
|
`docs/evidence/user-engine-operability-2026-07-29.json`.
|
|
|
|
The remaining production gaps are registry publication and an independently
|
|
custodied/off-node backup copy; the current PVC shares reef-railiance's single
|
|
failure domain, so T05 remains in progress.
|
|
|
|
2026-07-30 follow-up: both former gaps are implemented. The activity-core
|
|
ExternalSecret boundary published the portal and provisioner images to
|
|
`forgejo.coulomb.social` without exposing the package credential. Anonymous
|
|
digest inspection passed, and both live Deployments now pull immutable public
|
|
digests. The prior verified portal image is also published by digest;
|
|
rollback/roll-forward passed without node-local image reliance.
|
|
|
|
The established Option A activity-core lane produced and uploaded
|
|
`user-engine-pg-user_engine-20260729T220653Z.dump.age` to independent
|
|
Nextcloud custody. The plaintext dump was removed immediately and only
|
|
non-secret sizes and the artifact name were recorded. The local isolated
|
|
restore drill already proves the same logical dump/restore path.
|
|
|
|
2026-07-30 completion: the approved ops-mason construction plan established
|
|
the exact OpenBao KV path `platform/workloads/user-engine/runtime`, an
|
|
exact-path read policy, and separate bounded AppRoles for the `user-engine`
|
|
and `sso` External Secrets consumers. Namespace-restricted stores and three
|
|
ExternalSecrets preserve the existing application Secret interfaces.
|
|
|
|
A coordinated rotation rehearsal changed both runtime values at the
|
|
authoritative path, waited for all three derived Secrets to converge, and
|
|
returned both Deployments to Ready. Post-rotation checks proved matching
|
|
provisioner tokens, exact-path `read`, sibling-path `deny`, and a complete
|
|
disposable provision/drift/reconcile/deprovision lifecycle. No credential
|
|
value entered recorded output. All T05 acceptance criteria are complete.
|
|
|
|
## T06 - Prove role-scoped administration and failure safety
|
|
|
|
```task
|
|
id: NK-WP-0023-T06
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "f5f0d5d0-09fa-59de-b83f-7a6d4ff736a8"
|
|
```
|
|
|
|
Run end-to-end conformance for registration, login, MFA, tenant creation,
|
|
first-admin bootstrap, invitations, suspension/reactivation, cross-tenant
|
|
denial, platform-admin-only actions, provider outages, replay/idempotency,
|
|
backup restore, and reconciliation after partial failure.
|
|
|
|
2026-07-28 evidence: deployed-path health, service authentication, directory
|
|
creation, replay-safe linking, tenant user/admin group creation, and cleanup
|
|
passed. The test also detected and corrected newline handling for mounted
|
|
Kubernetes secrets before any identity was created. The broader negative,
|
|
outage, suspension, restore, and browser/MFA matrix remains.
|
|
|
|
2026-07-29 increment: provider-path conformance now also covers
|
|
machine-readable drift detection, automated repair, compensation semantics,
|
|
transient retry, and replay-safe deletion. The broader browser, authorization,
|
|
provider-outage, and restore matrix remains open.
|
|
|
|
2026-07-29 operability evidence adds an isolated database restore and a
|
|
reversible deployment rollback/roll-forward cycle. Backup and metrics access
|
|
are secret-free in recorded evidence. Independent disaster-recovery custody
|
|
and the remaining browser/provider-outage matrix keep T06 open.
|
|
|
|
## T07 - Complete KEY-WP-0004 through the reusable portal
|
|
|
|
```task
|
|
id: NK-WP-0023-T07
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "04664946-c38d-50e8-bc3f-5533801494d8"
|
|
```
|
|
|
|
Use the production portal to onboard
|
|
`bernd.worsch@binky-hedgehog.com` into `tenant:friendly:binky`, complete
|
|
OIDC/PKCE + MFA, and verify the Binky-only tenant-admin token and lifecycle
|
|
controls. Publish only non-secret evidence to `KEY-WP-0004-T02/T07`, then
|
|
finish that workplan.
|
|
|
|
2026-07-28: the deployed versioned portal API created the Binky tenant-admin
|
|
user and membership and provisioned/linked its LLDAP identity. The provider
|
|
correctly reports `password_setup_required`. During this flow a newline in the
|
|
mounted trusted-proxy Secret proved HTTP-incompatible; user-engine `0ef2ae5`
|
|
normalizes runtime transport whitespace, has 105 passing tests, and is live.
|
|
LLDAP SMTP is not configured, so first-password handoff and MFA/claim
|
|
acceptance remain rather than falling back to an operator-set password.
|
|
|
|
2026-07-29 complete: the reusable portal issued the password handoff, the
|
|
Binky user selected the password and enrolled TOTP, and a fresh login produced
|
|
Binky-only groups, roles `user` + `tenant-admin`, and AAL2 `pwd` + `otp`.
|
|
Administration of both `tenant:platform` and `tenant:coulomb` was denied.
|
|
|
|
## T08 - Document enterprise integration extension points
|
|
|
|
```task
|
|
id: NK-WP-0023-T08
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "83a00e26-aab9-51f1-afb4-cb5d354ab436"
|
|
```
|
|
|
|
Document later adapters for customer IdPs/directories, SAML/OIDC federation,
|
|
SCIM, JIT provisioning, directory group mapping, customer-owned offboarding,
|
|
and conflict/freshness rules. Keep `NK-WP-0011` demand-triggered; this task
|
|
defines compatibility seams, not enterprise implementation.
|
|
|
|
2026-07-29: added
|
|
`docs/user-engine-enterprise-identity-extension-points.md`, covering OIDC/SAML
|
|
federation, SCIM, JIT, group mapping, provenance, source ownership,
|
|
conflict/freshness rules, offboarding, failure behavior, and demand triggers
|
|
without starting the demand-gated enterprise implementation.
|
|
|
|
## Milestone closure (2026-07-30)
|
|
|
|
The live Binky MVP consumes verified KeyCape claims, enforces tenant/platform
|
|
role separation through user-engine's authorization port, correlates durable
|
|
audit/outbox records, and keeps password and MFA interactions on
|
|
NetKingdom-owned surfaces. Role-scoped administration, platform and unrelated
|
|
tenant denial, AAL2 login, drift/reconciliation, replay-safe deletion, restore,
|
|
rollback, secret rotation, and dependency failure/recovery are proven.
|
|
|
|
Replacing the pre-production authorization adapter with a deployed flex-auth
|
|
policy package, invitation mail, operated outbox replay/dead-letter delivery,
|
|
and the broader integration failure matrix transfer explicitly to
|
|
`NK-WP-0024`; they are not claimed as part of this completed milestone.
|