Complete user-engine boundary contracts

This commit is contained in:
2026-05-22 22:26:36 +02:00
parent 69c57f8af5
commit 97423c6110
4 changed files with 365 additions and 11 deletions

View File

@@ -24,6 +24,9 @@ NetKingdom is a self-optimizing security platform for Kubernetes-based IT infras
canonical spec: `canon/standards/iam-profile_v0.2.md`)
- SSO/MFA Platform: Keycloak with LDAP/Entra federation, enterprise identity (NK-WP-0001)
- Local Identity: file-based user store + minimal OIDC server for bootstrap phase (NK-WP-0002)
- User Engine Boundary Contract: source-of-truth, membership,
application-onboarding, projection, authorization, and audit contracts for
`user-engine` integration (`canon/standards/user-engine-boundary-contract_v0.1.md`)
- Security bootstrapping: credential management, SOPS/age integration, OpenBao runtime secret authority
- Architectural decisions (DECISIONS.md): identity source, secrets, GitOps, bootstrap user store
@@ -117,3 +120,5 @@ keywords: [bootstrap, local-identity, oidc, minimal, dev, sandbox]
- Start with: `wiki/` (specifications and decisions), `DECISIONS.md` (key architectural choices D1D5)
- Key files / directories: `sso-mfa/` (NK-WP-0001 active workplan), `local-identity/` (NK-WP-0002), `workplans/`
- Entry points: `workplans/NK-WP-0001-sso-mfa-platform.md` and `NK-WP-0002-local-identity.md` for current work
- User-domain boundary contract:
`canon/standards/user-engine-boundary-contract_v0.1.md`

View File

@@ -0,0 +1,327 @@
---
id: netkingdom-user-engine-boundary-contract
type: standard
title: "NetKingdom User Engine Boundary Contract v0.1"
domain: netkingdom
status: accepted
version: "0.1"
created: "2026-05-22"
updated: "2026-05-22"
scope: user-domain-boundaries
workplan:
- workplans/NK-WP-0014-user-engine-preparation-boundary-contracts.md
related:
- canon/standards/iam-profile_v0.2.md
- canon/standards/playbook-capability-contract_v0.1.md
- docs/responsibility-map.md
- docs/user-engine-interface-guidance.md
- docs/reviews/2026-05-22T19-19-59+0200-user-engine-architecture-review.md
---
# NetKingdom User Engine Boundary Contract v0.1
## Purpose
This contract defines how `user-engine` integrates into the NetKingdom
landscape without duplicating IAM, authorization, application registration,
deployment, audit, or UI responsibilities.
`user-engine` owns user-domain facts and profile projections. NetKingdom owns
the cross-repo boundary contract. Implementations and adapters must preserve
the ownership rules below even when they use local fixtures for development or
standalone deployments.
## Ownership Model
`user-engine` is a headless user-domain and profile service. It is not an
identity provider, MFA system, policy decision point, runtime secret store,
deployment engine, or UI repository.
| Concern | Owner | user-engine responsibility |
| --- | --- | --- |
| OIDC discovery, login, token issuance | `key-cape`, Keycloak, or `local-identity` in dev | Consume verified IAM Profile claims |
| Passwords, passkeys, sessions, MFA | IAM/MFA stack | No storage or lifecycle responsibility |
| Stable identity links | user-engine | Map `(issuer, subject)` to `user_id` |
| Account lifecycle and profile facts | user-engine | Canonical source of truth |
| Product memberships | user-engine unless explicitly imported | Own, validate, export as read models |
| Coarse authentication groups and roles | IAM provider normalized through the IAM Profile | Consume as actor facts |
| Fine-grained authorization | `flex-auth` | Ask, enforce, and audit decisions |
| Runtime secrets | OpenBao/Railiance platform services | Consume scoped secret references through adapters |
| Deployment mechanics | Railiance and application repos | Publish requirements and readiness signals |
| Self-service/admin UI | future UI repos | Provide APIs and projections only |
## Source-Of-Truth Matrix
| Resource kind | Source of truth | user-engine relation | Boundary rule |
| --- | --- | --- | --- |
| OIDC issuer and discovery metadata | IAM Profile implementation | Consume issuer metadata and JWKS through adapters | Never hardcode provider-specific paths where discovery is available |
| Login, session, MFA, and token lifecycle | `key-cape`, Keycloak, or `local-identity` in non-production | Accept only verified claim envelopes | user-engine must not issue, refresh, or revoke tokens |
| Identity claims | IAM Profile implementation | Normalize into an actor envelope | Claims are authentication facts, not final authorization decisions |
| Human subject | IAM provider for authentication identity; user-engine for domain record | Link `(issuer, subject)` to `user_id` | Email, username, and display name are mutable attributes, not keys |
| Local/bootstrap identities | `local-identity` | Allowed only in local/test/standalone modes | Production adapters must reject local or loopback issuers |
| User record | user-engine | Canonical owner | Other systems may reference `user_id` but must not mutate the record directly |
| Account lifecycle | user-engine | Canonical owner | IAM disablement may trigger import/sync events, but user-engine records lifecycle state |
| Groups | IAM provider | Consume from claims or imports as identity facts | Groups do not overwrite user-engine-owned memberships |
| Coarse roles | IAM provider, normalized into `roles` | Consume as actor facts for policy input | Roles are not user-engine resource ownership |
| Fine-grained roles, scopes, policies | `flex-auth` | Register resources/actions and request decisions | user-engine does not interpret policy packages locally in production |
| Tenant identifiers | NetKingdom/IAM Profile contract | Store tenant-scoped records and memberships | Tenant admin authority never implies `tenant:platform` authority |
| Product memberships | user-engine unless an import contract says otherwise | Canonical owner for local facts | Every imported membership carries source, version, freshness, and delete semantics |
| External/provisioned memberships | Provisioning system under import contract | Store as externally mastered facts | user-engine may expose/read them but must not silently take ownership |
| Applications as profile consumers | user-engine | Own application record and allowed profile scopes | Does not replace IAM clients, protected systems, or deployments |
| OIDC clients | IAM provider | Store binding metadata only | Client secrets and redirect validation stay with IAM |
| Protected systems | `flex-auth` | Store binding metadata and resource/action vocabulary reference | flex-auth remains PDP and protected-system registry owner |
| Catalog namespaces | user-engine | Canonical owner and validator | Namespaces bind to one owning application and version policy |
| Profile and preference values | user-engine | Canonical owner | Attribute definitions must resolve to a catalog namespace or governed global key |
| Effective-profile projections | user-engine | Canonical resolver and projection API | Projections are read models with version/freshness metadata |
| Claims enrichment inputs | IAM-side adapter | Optional profile read from user-engine | Adapter owns cache, freshness, and failure mode; login must not synchronously depend on user-engine |
| Runtime secrets and DB credentials | OpenBao/Railiance platform services | Consume logical secret names through `SecretProvider` | Secret values must not be stored in profile/catalog records |
| Deployment metadata | Railiance/application repo | Store binding references where needed for onboarding | Railiance executes deployment and readiness mechanics |
| Authorization decisions | `flex-auth` | Enforce returned decisions and obligations | Sensitive writes fail closed when decisions are unavailable |
| Local audit record | user-engine | Canonical owner for local mutation trail | Must carry correlation fields to decision and event records |
| Decision audit | `flex-auth` | Store returned decision id | user-engine audit must link to the decision id where a check occurred |
| Platform audit sink | NetKingdom/Railiance audit service | Emit redacted summaries | Sensitive profile payloads are not exported by default |
| Domain events | user-engine outbox | Canonical source for user-domain lifecycle events | Events are durable after commit and carry schema/version identifiers |
## Membership Synchronization Contract
Every membership fact that crosses a system boundary must carry this envelope:
| Field | Requirement |
| --- | --- |
| `membership_id` | Stable id for the fact in the owning system |
| `owner_system` | One of `user-engine`, `iam`, `provisioning`, or another explicit source |
| `source_system` | System that last supplied the fact |
| `subject_user_id` | user-engine `user_id` when resolved |
| `issuer` and `subject` | Original identity key when a user link is not yet resolved |
| `tenant` | Tenant context such as `tenant:platform` or `tenant:coulomb` |
| `scope_type` | `tenant`, `application`, `team`, `catalog`, or a contract extension |
| `scope_id` | Stable id inside the scope type |
| `relation` | Role, relation, or membership kind |
| `freshness` | Timestamp, version, sequence, or lease/expiry marker |
| `delete_semantics` | `tombstone`, `disable`, `expire`, or `hard_delete_requested` |
| `conflict_rule` | `owner_wins`, `newer_version_wins`, or an explicit manual-review rule |
| `correlation_id` | Request/import/export correlation id |
Allowed ownership classes:
| Class | Rule |
| --- | --- |
| `user_engine_mastered` | Created and mutated in user-engine; exported outward as read models only |
| `iam_imported_seed` | IAM group/role data may seed a local membership once, but does not continue overwriting it unless a contract says so |
| `externally_provisioned` | Provisioning source remains owner; user-engine stores the fact with source/version/delete semantics |
| `flex_auth_export` | user-engine exports subject facts to flex-auth for policy input; flex-auth does not become the membership store |
| `iam_export_requested` | Optional adapter-owned export for coarse IAM groups/claims; user-engine remains owner unless explicitly transferred |
Conflict handling:
- owner wins by default;
- non-owner updates are rejected or stored as pending import review;
- stale imports are ignored when their freshness marker is older than the
current fact;
- cross-tenant imports must be rejected unless the import contract explicitly
maps source tenant to target tenant;
- deletes from a non-owner source disable only that source's externally
mastered fact and must not remove user-engine-owned memberships.
Freshness and invalidation:
- membership writes emit outbox events with a version stamp;
- exports to flex-auth carry the membership version used to build the subject
fact;
- consumers must be able to tell whether an authorization decision used stale
membership facts;
- high-risk membership changes invalidate request caches and short-lived
decision caches.
## Application Onboarding Contract
A platform application is represented by several records. They are bound
together, but not merged into one ownership domain.
| Binding | Owner | Required fields |
| --- | --- | --- |
| user-engine application | user-engine | `application_id`, display name, owner, allowed profile scopes, projection types, lifecycle state |
| IAM OIDC client | `key-cape` or Keycloak | client id, issuer, redirect URIs, allowed scopes, assurance requirements |
| flex-auth protected system | `flex-auth` | protected-system id, resource/action vocabulary, policy package binding |
| Catalog namespace | user-engine | namespace, owning application id, catalog id, versioning and deprecation policy |
| Deployment metadata | Railiance/application repo | environment, service name, tenant placement, ingress/readiness endpoints |
| Audit/event identity | user-engine plus platform sink | source application id, event subject prefix, correlation-id policy |
Minimum binding record:
```yaml
application_id: string
tenant_scope: string
iam:
issuer: string
oidc_client_id: string
flex_auth:
protected_system_id: string
resource_vocabulary_version: string
catalog:
namespace: string
active_catalog_version: string
deployment:
environment: string
service_name: string
audit:
event_source: string
correlation_policy: required
```
Safe onboarding checklist:
1. Register or approve the application owner and tenant scope.
2. Create the IAM OIDC client with redirect URIs, scopes, and assurance
requirements.
3. Register the flex-auth protected system and policy package.
4. Create the user-engine application record and bind the IAM/flex-auth ids.
5. Register the catalog namespace and publish the first catalog version.
6. Define projection types the application may request.
7. Register event source and audit redaction rules.
8. Record Railiance deployment metadata and readiness endpoints.
9. Verify one authorized profile read, one denied profile read, one authorized
mutation, one denied mutation, and correlated audit/event output.
## Projection And Claims-Enrichment Boundaries
Projection types are distinct contracts:
| Projection type | Consumer | Required boundary |
| --- | --- | --- |
| `self_service` | Current user | Includes only fields visible/editable by the subject under policy |
| `admin` | Tenant or platform admin tools | Requires flex-auth checks and tenant/platform authority separation |
| `application_runtime` | Registered applications | Limited to allowed profile scopes and catalog namespace bindings |
| `audit` | Operators and audit sinks | Redacted summaries with correlation metadata, not full sensitive payloads |
| `agent_context` | Autonomous or delegated agents | Policy-filtered context with actor/delegation evidence |
| `claims_enrichment` | IAM-side enrichment adapter | Optional, cache/freshness governed, and never token issuance itself |
Required projection metadata:
- projection type;
- target user id;
- tenant and application context;
- catalog/profile version stamps;
- redaction policy used;
- authorization decision id where a decision was needed;
- freshness timestamp;
- correlation id.
Claims enrichment rules:
- user-engine must not issue tokens;
- IAM owns token issuance and the enrichment adapter;
- enrichment adapters must define cache TTL, stale-read policy, and failure
behavior;
- privileged or destructive login claims must not depend on stale profile
enrichment;
- when user-engine is unavailable, the adapter either omits optional enriched
claims or fails according to IAM-side policy, not user-engine policy.
## Authorization Contract
user-engine is a policy enforcement point. `flex-auth` is the policy decision
point for production authorization decisions.
Minimum authorization request:
```yaml
actor:
issuer: string
subject: string
tenant: string
principal_type: human | service | agent
roles: [string]
groups: [string]
scopes: [string]
assurance: object
resource:
type: string
id: string
action: string
context:
tenant: string
application_id: string | null
target_user_id: string | null
projection_type: string | null
correlation_id: string
```
Resource/action vocabulary:
| Resource | Baseline actions |
| --- | --- |
| `user-engine:user` | `read`, `create`, `update`, `deactivate`, `delete_request` |
| `user-engine:identity-link` | `read`, `link`, `unlink` |
| `user-engine:profile` | `read`, `update`, `resolve`, `project` |
| `user-engine:membership` | `read`, `assign`, `remove`, `import`, `export` |
| `user-engine:application` | `register`, `read`, `update`, `deactivate` |
| `user-engine:catalog` | `register`, `activate`, `deprecate`, `migrate` |
| `user-engine:projection` | `read`, `render`, `invalidate` |
| `user-engine:audit` | `read`, `export_summary` |
Performance model:
- single sensitive writes use synchronous flex-auth checks and fail closed;
- list screens and bulk admin operations should use batch checks;
- request-scoped memoization is allowed for identical checks within one
request;
- short-lived decision caches are allowed only for low-risk reads when the
policy package permits caching and names invalidation events;
- local policy fixtures are allowed only for tests and standalone development;
- production adapters must record the flex-auth decision id or equivalent
decision correlation.
## Audit Correlation Contract
Every user-engine mutation and sensitive read must create or reference a
correlation bundle:
| Field | Requirement |
| --- | --- |
| `correlation_id` | Stable id propagated across request, decision, audit, and event records |
| `request_id` | Transport/request id where available |
| `actor` | IAM Profile actor envelope or redacted service/agent equivalent |
| `tenant` | Tenant context for the action |
| `application_id` | Application context where applicable |
| `target_user_id` | Target user where applicable |
| `resource` and `action` | user-engine resource/action pair |
| `authorization_decision_id` | flex-auth decision id when an authorization check occurred |
| `user_engine_audit_id` | Local audit record id |
| `outbox_event_id` | Event id when a domain event is emitted |
| `redaction_policy` | Policy used to summarize sensitive fields |
| `change_summary` | Redacted mutation summary |
Platform audit sinks receive summaries. They must not receive full profile
payloads, secret values, or catalog-sensitive values unless a future contract
explicitly authorizes that export path.
## user-engine Repo Readiness
The user-engine repository may start production-code implementation when these
artifacts exist and remain aligned with this contract:
| Artifact | Required purpose | Current expected path |
| --- | --- | --- |
| Scope boundary | State in/out-of-scope responsibilities | `/home/worsch/user-engine/SCOPE.md` |
| Architecture notes | Explain IAM, flex-auth, platform, UI, and deployment boundaries | `/home/worsch/user-engine/wiki/ArchitectureBlueprint.md` |
| Repo layout decision | Keep domain logic independent from transports and adapters | `/home/worsch/user-engine/docs/development.md` |
| Local development contract | Define standalone vs platform configuration and guardrails | `/home/worsch/user-engine/docs/configuration.md` |
| NetKingdom integration notes | Translate this contract into repo-local ports/adapters | `/home/worsch/user-engine/docs/interfaces/netkingdom-integration.md` |
| Implementation workplans | Carry implementation tasks in user-engine, not NetKingdom | `/home/worsch/user-engine/workplans/USER-WP-0001` through `USER-WP-0006` |
Readiness checklist:
- source-of-truth boundaries are documented before new stores are added;
- membership imports/exports identify owner, source, freshness, and delete
semantics;
- application records bind, but do not own, IAM clients and flex-auth protected
systems;
- projections include version/freshness and redaction metadata;
- claims enrichment is optional and adapter-owned;
- authorization ports can support synchronous, batch, memoized, and safe-cache
modes;
- audit records can correlate with flex-auth decisions and outbox events;
- implementation work remains in user-engine workplans while NetKingdom keeps
only boundary and orchestration responsibilities.

View File

@@ -1,10 +1,12 @@
# User Engine Interface Guidance
Status: initial interface guidance
Status: accepted interface guidance
Date: 2026-05-22
Owner: NetKingdom
Canonical contract: `canon/standards/user-engine-boundary-contract_v0.1.md`
Related:
- `canon/standards/user-engine-boundary-contract_v0.1.md`
- `docs/reviews/2026-05-22T19-19-59+0200-user-engine-architecture-review.md`
- `docs/responsibility-map.md`
- `canon/standards/iam-profile_v0.2.md`
@@ -12,9 +14,12 @@ Related:
## Purpose
This document defines the cross-repo interface guidance for integrating
This document summarizes the cross-repo interface guidance for integrating
`user-engine` into the NetKingdom landscape without duplicating identity,
authorization, deployment, or UI responsibilities.
authorization, deployment, audit, or UI responsibilities. The normative
versioned contract is
`canon/standards/user-engine-boundary-contract_v0.1.md`; this document remains
as the shorter implementation-facing guide.
`user-engine` owns user-domain facts and profile projections. NetKingdom owns
the security and orchestration contracts that decide how those facts relate to

View File

@@ -4,7 +4,7 @@ type: workplan
title: "User Engine Preparation And Boundary Contracts"
domain: netkingdom
repo: net-kingdom
status: ready
status: finished
owner: codex
topic_slug: netkingdom
planning_priority: high
@@ -68,7 +68,7 @@ Out of scope:
```task
id: NK-WP-0014-T1
status: todo
status: done
priority: high
state_hub_task_id: "4e941174-ac55-4f6e-8568-40f45b1ed821"
```
@@ -84,7 +84,7 @@ be hardened into versioned contracts as implementation feedback arrives.
```task
id: NK-WP-0014-T2
status: todo
status: done
priority: high
state_hub_task_id: "5ddc46bb-6238-4944-a023-d8b46b410c76"
```
@@ -96,7 +96,7 @@ tenant boundaries are represented.
```task
id: NK-WP-0014-T3
status: todo
status: done
priority: high
state_hub_task_id: "696bc65b-0f8d-47b5-bccc-65ed285b42e6"
```
@@ -108,7 +108,7 @@ for adding one new application safely.
```task
id: NK-WP-0014-T4
status: todo
status: done
priority: high
state_hub_task_id: "99ab4535-cbbf-4e13-a2c5-adfc814d5aeb"
```
@@ -120,7 +120,7 @@ claims enrichment is adapter-owned and cache/freshness governed.
```task
id: NK-WP-0014-T5
status: todo
status: done
priority: medium
state_hub_task_id: "d35a1356-a9fe-4cf3-8fb0-6f45cfbbccee"
```
@@ -132,7 +132,7 @@ decision IDs and platform audit sinks.
```task
id: NK-WP-0014-T6
status: todo
status: done
priority: medium
state_hub_task_id: "04fd2f92-3aa4-468d-9e9e-9b092890507e"
```
@@ -157,8 +157,25 @@ NetKingdom documents per ADR-0010.
- NetKingdom responsibility-map updates are either applied or explicitly
deferred until user-engine becomes a shared platform service.
## Completion Notes
Completed on 2026-05-22:
- Added the canonical versioned contract at
`canon/standards/user-engine-boundary-contract_v0.1.md`.
- Promoted `docs/user-engine-interface-guidance.md` to an implementation guide
that points at the canonical contract.
- Confirmed `docs/responsibility-map.md` already includes `user-engine` as an
orchestrated repository and names NetKingdom's boundary responsibilities.
- Confirmed `/home/worsch/user-engine` already carries the required repo-local
preparation artifacts: `SCOPE.md`, `wiki/ArchitectureBlueprint.md`,
`docs/development.md`, `docs/configuration.md`,
`docs/interfaces/netkingdom-integration.md`, and `USER-WP-0001` through
`USER-WP-0006`.
## Dependencies And Sequencing
- Depends on NK-WP-0012 for IAM Profile consumption rules.
- Depends on NK-WP-0013 for NetKingdom meta-orchestration conventions.
- Gates NK-WP-0015.
- Gates implementation work in `/home/worsch/user-engine`, now tracked as
`USER-WP-0001` through `USER-WP-0006`.