From 39b71d6d96cd89d36473dfa7536a13919c385799 Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 30 Jul 2026 00:40:43 +0200 Subject: [PATCH] Complete user-engine runtime custody --- WORK-RECORDS.md | 2 +- .../user-engine-operability-2026-07-29.json | 8 ++ sso-mfa/k8s/user-engine/README.md | 7 +- sso-mfa/k8s/user-engine/openbao-runtime.yaml | 122 ++++++++++++++++++ ...user-engine-portal-platform-integration.md | 21 ++- 5 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 sso-mfa/k8s/user-engine/openbao-runtime.yaml diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index d2abad8..936c4c6 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -53,7 +53,7 @@ | task | NK-WP-0023-T02 | done | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | | task | NK-WP-0023-T03 | done | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | | task | NK-WP-0023-T04 | wait | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | -| task | NK-WP-0023-T05 | progress | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | +| task | NK-WP-0023-T05 | done | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | | task | NK-WP-0023-T06 | wait | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | | task | NK-WP-0023-T07 | done | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | | task | NK-WP-0023-T08 | done | — | workplans/NK-WP-0023-user-engine-portal-platform-integration.md | diff --git a/docs/evidence/user-engine-operability-2026-07-29.json b/docs/evidence/user-engine-operability-2026-07-29.json index 53a7137..ac23d43 100644 --- a/docs/evidence/user-engine-operability-2026-07-29.json +++ b/docs/evidence/user-engine-operability-2026-07-29.json @@ -8,12 +8,20 @@ "identity_provisioner_registry_public_read": true, "metrics_authorized": true, "metrics_unauthorized_denied": true, + "openbao_exact_path_read": true, + "openbao_sibling_path_denied": true, + "openbao_runtime_authoritative": true, "restore_drill_complete": true, "restore_migration_rows": 1, "restore_public_tables": 4, "rollback_exercised": true, "rollforward_restored": true, "user_engine_offsite_age_upload": true, + "runtime_rotation_rehearsed": true, + "runtime_externalsecrets_ready": 3, + "runtime_deployments_ready_after_rotation": 2, + "provisioner_derived_tokens_equal": true, + "post_rotation_identity_reconciliation": true, "user_engine_registry_public_read": true }, "declared_image": "forgejo.coulomb.social/coulomb/user-engine@sha256:60f4fa1c144c8f7b9e2e74c264e4594e63ac6a0c0f75e5cf536880b8fd99fa28", diff --git a/sso-mfa/k8s/user-engine/README.md b/sso-mfa/k8s/user-engine/README.md index 3a13f2c..61694c2 100644 --- a/sso-mfa/k8s/user-engine/README.md +++ b/sso-mfa/k8s/user-engine/README.md @@ -13,10 +13,13 @@ package read was verified without an image pull Secret; publishing still uses the ExternalSecret-backed credential and temporary client state. The CloudNativePG operator creates `user-engine-pg-app`, including its `uri` -field. `user-engine-runtime` contains only the generated edge marker and must -be replaced by an ExternalSecret before public exposure. +field. OpenBao is authoritative for the portal edge marker and provisioner +service token at `platform/workloads/user-engine/runtime`. The +`openbao-runtime.yaml` stores and ExternalSecrets deliver those values into the +existing namespaced Secret names without changing application interfaces. ```bash +kubectl apply -f openbao-runtime.yaml kubectl apply -f runtime.yaml kubectl -n user-engine rollout status deployment/user-engine kubectl -n user-engine get cluster,pod,service,networkpolicy diff --git a/sso-mfa/k8s/user-engine/openbao-runtime.yaml b/sso-mfa/k8s/user-engine/openbao-runtime.yaml new file mode 100644 index 0000000..dedcbd5 --- /dev/null +++ b/sso-mfa/k8s/user-engine/openbao-runtime.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: openbao-user-engine-runtime + labels: + app.kubernetes.io/part-of: net-kingdom-sso-mfa + net-kingdom/component: secret-delivery +spec: + conditions: + - namespaces: [user-engine] + provider: + vault: + server: https://bao.coulomb.social + path: platform + version: v2 + auth: + appRole: + path: approle + roleRef: + name: openbao-user-engine-runtime-approle + namespace: external-secrets + key: role-id + secretRef: + name: openbao-user-engine-runtime-approle + namespace: external-secrets + key: secret-id +--- +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: openbao-sso-user-engine-runtime + labels: + app.kubernetes.io/part-of: net-kingdom-sso-mfa + net-kingdom/component: secret-delivery +spec: + conditions: + - namespaces: [sso] + provider: + vault: + server: https://bao.coulomb.social + path: platform + version: v2 + auth: + appRole: + path: approle + roleRef: + name: openbao-sso-user-engine-runtime-approle + namespace: external-secrets + key: role-id + secretRef: + name: openbao-sso-user-engine-runtime-approle + namespace: external-secrets + key: secret-id +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: user-engine-runtime + namespace: user-engine + labels: + app.kubernetes.io/name: user-engine + app.kubernetes.io/part-of: user-engine +spec: + refreshInterval: 5m + secretStoreRef: + kind: ClusterSecretStore + name: openbao-user-engine-runtime + target: + name: user-engine-runtime + creationPolicy: Merge + deletionPolicy: Retain + data: + - secretKey: proxy-secret + remoteRef: + key: workloads/user-engine/runtime + property: PROXY_SECRET +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: identity-provisioner-client + namespace: user-engine + labels: + app.kubernetes.io/name: user-engine + app.kubernetes.io/part-of: user-engine +spec: + refreshInterval: 5m + secretStoreRef: + kind: ClusterSecretStore + name: openbao-user-engine-runtime + target: + name: identity-provisioner-client + creationPolicy: Merge + deletionPolicy: Retain + data: + - secretKey: token + remoteRef: + key: workloads/user-engine/runtime + property: PROVISIONER_TOKEN +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: identity-provisioner-token + namespace: sso + labels: + app.kubernetes.io/name: identity-provisioner + app.kubernetes.io/part-of: net-kingdom-sso-mfa +spec: + refreshInterval: 5m + secretStoreRef: + kind: ClusterSecretStore + name: openbao-sso-user-engine-runtime + target: + name: identity-provisioner-token + creationPolicy: Merge + deletionPolicy: Retain + data: + - secretKey: token + remoteRef: + key: workloads/user-engine/runtime + property: PROVISIONER_TOKEN diff --git a/workplans/NK-WP-0023-user-engine-portal-platform-integration.md b/workplans/NK-WP-0023-user-engine-portal-platform-integration.md index a90fcb6..65a1110 100644 --- a/workplans/NK-WP-0023-user-engine-portal-platform-integration.md +++ b/workplans/NK-WP-0023-user-engine-portal-platform-integration.md @@ -8,7 +8,7 @@ status: active owner: codex topic_slug: netkingdom created: "2026-07-27" -updated: "2026-07-28" +updated: "2026-07-30" depends_on: - USER-WP-0020 - KEY-WP-0004 @@ -153,7 +153,7 @@ delivery with replay and dead-letter evidence. ```task id: NK-WP-0023-T05 -status: progress +status: done priority: high state_hub_task_id: "4ef00e05-1259-4c76-a8ef-ec40b5facd1c" ``` @@ -207,11 +207,18 @@ 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. -The final T05 custody residual is narrower: `user-engine-runtime/proxy-secret` -and `identity-provisioner-client/token` remain bootstrap Kubernetes Secrets. -They must move to an OpenBao-owned path plus ExternalSecret and a rotation -procedure. Creating that new write/custody lane requires the ops-mason -executive approval gate; registry and backup work do not remain open. +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