Deploy user-engine authorization policy
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

This commit is contained in:
tegwick 2026-08-09 02:21:29 +02:00
parent 5217109103
commit ccf4b509be
5 changed files with 141 additions and 5 deletions

View file

@ -0,0 +1,13 @@
# user-engine policy service
Dynamic human subjects arrive as verified KeyCape claims, so the registry
defines the protected system while the policy evaluates tenant, roles, and
self context from each request. Platform operators may cross tenants;
tenant administrators and self-service users may not.
Validate with:
```bash
flex-auth test-policy -file examples/user-engine/policy_package.md
flex-auth load-registry -file examples/user-engine/registry_snapshot.json
```

View file

@ -0,0 +1,8 @@
[
{"id":"self-allow","request":{"id":"c1","tenant":"tenant:friendly:binky","subject":{"id":"u1","type":"human","tenant":"tenant:friendly:binky","attributes":{"roles":[]}},"action":"me.read","resource":{"id":"u1","type":"user-engine:me","system":"user-engine","tenant":"tenant:friendly:binky"},"context":{"self":true}},"expect":{"effect":"allow","reason":"self_service"}},
{"id":"tenant-admin-allow","request":{"id":"c2","tenant":"tenant:friendly:binky","subject":{"id":"admin","type":"human","tenant":"tenant:friendly:binky","attributes":{"roles":["tenant-admin"]}},"action":"family_member.invite","resource":{"id":"i1","type":"user-engine:family-invitation","system":"user-engine","tenant":"tenant:friendly:binky"},"context":{}},"expect":{"effect":"allow","reason":"tenant_admin"}},
{"id":"platform-allow","request":{"id":"c3","tenant":"tenant:friendly:binky","subject":{"id":"operator","type":"human","tenant":"platform:root","attributes":{"roles":["platform-operator"]}},"action":"tenant.diagnostics.read","resource":{"id":"tenant:friendly:binky","type":"user-engine:tenant","system":"user-engine","tenant":"tenant:friendly:binky"},"context":{}},"expect":{"effect":"allow","reason":"platform_operator"}},
{"id":"cross-tenant-deny","request":{"id":"c4","tenant":"tenant:friendly:binky","subject":{"id":"admin","type":"human","tenant":"tenant:family:other","attributes":{"roles":["tenant-admin"]}},"action":"membership.write","resource":{"id":"m1","type":"user-engine:membership","system":"user-engine","tenant":"tenant:friendly:binky"},"context":{}},"expect":{"effect":"deny","reason":"cross_tenant"}},
{"id":"missing-role-deny","request":{"id":"c5","tenant":"tenant:friendly:binky","subject":{"id":"u1","type":"human","tenant":"tenant:friendly:binky","attributes":{"roles":[]}},"action":"membership.write","resource":{"id":"m1","type":"user-engine:membership","system":"user-engine","tenant":"tenant:friendly:binky"},"context":{}},"expect":{"effect":"deny","reason":"no_matching_role_or_context"}},
{"id":"wrong-system-deny","request":{"id":"c6","tenant":"tenant:friendly:binky","subject":{"id":"operator","type":"human","tenant":"platform:root","attributes":{"roles":["platform-operator"]}},"action":"outbox.replay","resource":{"id":"e1","type":"user-engine:outbox-event","system":"other","tenant":"tenant:friendly:binky"},"context":{}},"expect":{"effect":"deny","reason":"wrong_system"}}
]

View file

@ -0,0 +1,83 @@
---
id: user-engine.portal.authorize
name: user-engine portal authorization
namespace: user-engine:portal
version: v1
status: ready
package: flexauth.user_engine.portal
actions:
- "*"
owner: team:platform-security
fixtures:
- policy_fixtures.yaml
caring:
profile: caring-0.4.0-rc2
enforce: false
canonical_roles: [Operator, Administrator, User]
organization_relations: [ServiceProvider, Customer]
scopes:
- {level: Platform, id: platform:user-engine, tenant: "platform:root"}
- {level: Tenant, id: tenant:dynamic}
planes: [Identity, Policy, Audit]
capabilities: [Read, Create, Update, Delete, Grant, Audit]
exposure_modes: [Metadata]
conditions: [Logged]
restrictions: [PrivilegeEscalationBlocked, TenantBoundary]
activation:
mode: local
metadata:
source: examples/user-engine/policy_package.md
flex_auth_contract: protected-system-v0
---
# user-engine portal authorization
The portal supplies verified identity claims. This policy enforces platform,
tenant, and self boundaries and denies unknown role/context combinations.
```rego
import future.keywords.if
import future.keywords.in
roles := object.get(object.get(input.subject, "attributes", {}), "roles", [])
subject_tenant := object.get(input.subject, "tenant", "")
resource_tenant := object.get(input.resource, "tenant", input.tenant)
self_request := object.get(input.context, "self", false)
decision := {"effect": "allow", "reason": "platform_operator"} if {
valid_system
"platform-operator" in roles
} else := {"effect": "allow", "reason": "tenant_admin"} if {
valid_system
same_tenant
"tenant-admin" in roles
} else := {"effect": "allow", "reason": "self_service"} if {
valid_system
same_tenant
self_request == true
} else := {"effect": "deny", "reason": first_denial} if { true }
valid_system if { input.resource.system == "user-engine" }
same_tenant if { subject_tenant != ""; subject_tenant == input.tenant; resource_tenant == input.tenant }
default first_denial := "no_matching_role_or_context"
first_denial := "wrong_system" if { not valid_system }
else := "cross_tenant" if { subject_tenant != ""; subject_tenant != input.tenant }
```
## Tests
```rego test
package flexauth.user_engine.portal_test
import future.keywords.if
import data.flexauth.user_engine.portal
base := {"tenant": "tenant:friendly:binky", "subject": {"id": "u1", "type": "human", "tenant": "tenant:friendly:binky", "attributes": {"roles": []}}, "action": "me.read", "resource": {"id": "u1", "type": "user-engine:me", "system": "user-engine", "tenant": "tenant:friendly:binky"}, "context": {"self": true}}
test_self_allowed if { portal.decision.effect == "allow" with input as base }
test_tenant_admin_allowed if { portal.decision.effect == "allow" with input as object.union(base, {"subject": object.union(base.subject, {"attributes": {"roles": ["tenant-admin"]}}), "context": {}}) }
test_platform_operator_cross_tenant_allowed if { portal.decision.effect == "allow" with input as object.union(base, {"subject": object.union(base.subject, {"tenant": "platform:root", "attributes": {"roles": ["platform-operator"]}}), "context": {}}) }
test_cross_tenant_denied if { portal.decision.reason == "cross_tenant" with input as object.union(base, {"subject": object.union(base.subject, {"tenant": "tenant:family:other"})}) }
test_missing_role_denied if { portal.decision.effect == "deny" with input as {"tenant": "tenant:friendly:binky", "subject": {"id": "u1", "type": "human", "tenant": "tenant:friendly:binky", "attributes": {"roles": []}}, "action": "membership.write", "resource": {"id": "m1", "type": "user-engine:membership", "system": "user-engine", "tenant": "tenant:friendly:binky"}, "context": {}} }
test_wrong_system_denied if { portal.decision.reason == "wrong_system" with input as object.union(base, {"resource": object.union(base.resource, {"system": "other"})}) }
```

View file

@ -0,0 +1,16 @@
{
"systems": [{
"id": "user-engine",
"name": "User Engine",
"resource_types": [
{"name":"user-engine:user","scope_level":"Resource","planes":["Identity","Audit"]},
{"name":"user-engine:membership","scope_level":"Resource","planes":["Identity","Policy","Audit"]},
{"name":"user-engine:family-invitation","scope_level":"Resource","planes":["Identity","Audit"]},
{"name":"user-engine:tenant","scope_level":"Tenant","planes":["Identity","Audit"]},
{"name":"user-engine:outbox","scope_level":"Platform","planes":["Audit"]}
],
"actions": [],
"metadata": {"flex_auth_contract":"protected-system-v0","dynamic_actions":true}
}],
"resource_manifests": [], "tenants": [], "subjects": [], "groups": [], "relationships": []
}

View file

@ -4,7 +4,7 @@ type: workplan
title: "Provide production authorization for user-engine"
domain: infotech
repo: flex-auth
status: ready
status: active
owner: codex
topic_slug: netkingdom
created: "2026-08-08"
@ -24,7 +24,7 @@ net-kingdom/docs/user-engine-platform-expansion-contract.md.
```task
id: FLEX-WP-0009-T01
status: todo
status: done
priority: high
state_hub_task_id: "e940c5a3-ecb4-43d3-9554-2bfb422ec56d"
```
@ -38,11 +38,15 @@ deny.
Done when all manifests validate and the vocabulary matches the action and
resource strings emitted by user-engine.
Done 2026-08-09: `examples/user-engine` defines the dynamic protected-system
registry and verified-claim request vocabulary for platform, tenant-admin,
self-service, cross-tenant, missing-role, and wrong-system cases.
## T02 - Implement and verify the policy package
```task
id: FLEX-WP-0009-T02
status: todo
status: done
priority: high
state_hub_task_id: "6e0fe708-d7ff-411f-a64d-84a1692a6e11"
```
@ -55,11 +59,14 @@ mismatch, cross-tenant, malformed-context, and stale-policy fixtures.
Done when fixture evaluation is deterministic, default deny is proven, and
decision envelopes contain stable decision IDs and policy provenance.
Done 2026-08-09: all six embedded Rego tests and all six request fixtures pass;
the package validates under CARING 0.4.0-rc2 and the registry loads cleanly.
## T03 - Deploy the cluster-local service
```task
id: FLEX-WP-0009-T03
status: todo
status: done
priority: high
state_hub_task_id: "f8293230-136d-4f2d-8d3f-bb9840ea7e63"
```
@ -72,11 +79,15 @@ NetworkPolicy, and ingress restricted to approved protected systems.
Done when user-engine can reach POST /v1/check, an unrelated namespace
cannot, and restart/rollback procedures are documented.
Done 2026-08-09: immutable digest `sha256:a31961c45215aa6baf3bc748c6741ab703c2c8325e61aa7983a355026195e51b`
is deployed as `flex-auth-user-engine.flex-auth.svc.cluster.local:8080`, Ready
behind ingress restricted to the user-engine workload and with no egress.
## T04 - Hand back production evidence
```task
id: FLEX-WP-0009-T04
status: todo
status: progress
priority: high
state_hub_task_id: "97b931e9-ac5b-46c7-a462-e23c0c18c4f4"
```
@ -87,3 +98,8 @@ policy version, and correlation IDs. Send completion evidence to NK-WP-0024.
Done when user-engine can replace its local authorization bridge without an
availability bypass and the deployed failure matrix remains fail closed.
2026-08-09 live evidence: from the user-engine pod, `live-self` returned allow
with decision `decision:4bf95ebb989ac628`; the cross-tenant variant returned
deny/cross_tenant with decision `decision:bab072ce3ee72d98`. Runtime activation
remains gated on the separately owned event and mail receivers.