secrets-engine/docs/bounded-executor-credential-lanes.md
tegwick 8ec5aff1a6
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
NK-WP-0056-T02 owner answer: bounded executor credential lanes; SECRETS-WP-0017 proposed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 994874@bnt-lap001
Assistant-Session: 6017c416-d619-47eb-bd1a-f670a02d7d87
2026-10-31 14:19:34 +01:00

9.1 KiB

Bounded executor credential lanes: owner answer to NK-WP-0056-T02

Status: proposal (secrets-engine owner answer, 2026-10-31). Nothing here is an approval, a grant, or a live change. Founder and platform-owner decisions are marked as such.

Request: net-kingdom/docs/proposals/2026-10-31-nk56-t02-owner-requests.md (section "secrets-engine"), hub message 16adf344-92da-443d-a25b-19dc29c5952a. Standard under review: NetKingdom Bounded Execution Admission v0.1 (proposed), example examples/bounded-execution-admission/bind-rotation-svc-authelia.yaml. Pilot executor: service:nk-bind-executor, Kubernetes ServiceAccount nk-bind-executor in namespace sso. Follow-on work: SECRETS-WP-0017.

What the engine does today (source facts)

Fact Source
Consumer lane policies are read-only: {data_path: ["read"]} plus optional metadata read. No consumer lane can write. src/secrets_engine/roles.py lane_policy_paths
Engine-operated delivery auth is AppRole only (VALID_DELIVERY_AUTH_METHODS = ("approle", "none")). Kubernetes/ESO/OIDC delivery is recorded as workload_delivery metadata and not operated. src/secrets_engine/catalog.py; SCOPE.md "Catalog and validation"
auth-capability lanes grant only update, and only on exact ssh/sign/<role>. roles.py AUTH_CAPABILITY_ALLOWED_CAPABILITIES and path check
The engine's own CAS write (provision) runs under the engine's stage credential from a mode-0600 file. It is not a capability handed to a workload. SCOPE.md "KV provisioning"; src/secrets_engine/provision.py
Every production live command currently fails closed (approval-claim endpoint not served). Task-scoped protected execution is designed, not shipped; the service-jwt identity (CCR-2026-0038) is login-only. pep-stance.yaml; docs/task-scoped-openbao-execution-contract.md; SECRETS-WP-0013
The existing NetKingdom bind lanes (CCR-2026-0052..0057) are platform-typed workload-kv-read / attended-delivery CCRs with Kubernetes auth roles applied by railiance-platform, not secrets-engine catalog lanes. railiance-platform/credential-change-requests/CCR-2026-0052..0057

Question 1: executor OpenBao capabilities (CAS write of svc-authelia, reads for checks)

Answer: not supported today; needs a change, split between two owners.

secrets-engine does not orchestrate this lane the way it orchestrates its AppRole lanes, for three reasons: the lane needs a write, the workload logs in with Kubernetes auth, and live production commands are gated. Routing the executor's write through secrets-engine serve was considered and rejected for the pilot. It would put T06 behind two unfinished gates (approval-claim and SECRETS-WP-0013), and the engine would then hold a write capability on behalf of the executor. The executor should hold only its own 15-minute token.

Proposed split:

  • railiance-platform (no CCR is created here) owns the Kubernetes auth role and the ACL policy. It applies them with a new CCR request type, for example workload-kv-rotate-cas, following the CCR-0052/0053 shape. It also sets cas_required=true on the svc-authelia secret's metadata. This is a one-time attended step. The executor has no metadata capability and cannot undo it.
  • secrets-engine catalogs the lane as non-secret metadata (delivery_auth.management: existing). It renders the expected policy from the catalog and refuses any platform policy file that differs from it. That check covers wildcards, metadata, delete/destroy and sys/ paths, and token creation. secrets-engine also gives a read-only route pointer. This is SECRETS-WP-0017.

Proposed lane shape (for founder and platform approval)

Item Proposal
Catalog id nk-bind-executor-svc-authelia (kind kv, stage prod, risk high)
Policy name net-kingdom-nk-bind-executor (must not use admin)
Write path platform/data/workloads/net-kingdom/directory-binds/svc-authelia: ["read", "update"]. There is no create: the path already exists (CAS=0 written in T04), so a deleted path cannot be recreated silently.
CAS cas_required=true on that secret's metadata (set by platform). The executor reads the current version from the data response, so it needs no metadata read.
Check read platform/data/workloads/net-kingdom/synthetic-journey/syn-journey: ["read"]
Denied (verified as denials) platform/metadata/..., platform/delete/..., platform/destroy/..., platform/undelete/... for both paths; sibling directory-binds/*; auth/token/create; sys/
Token self-lifecycle auth/token/lookup-self ["read"] and auth/token/revoke-self ["update"], with self-revoke in finally (same as the bind-lane pattern)
Auth Kubernetes mount kubernetes, role net-kingdom-nk-bind-executor, bound SA nk-bind-executor, namespace sso, audience openbao, bound_claims_confirmed: true
TTL ttl, token_max_ttl and token_explicit_max_ttl all 15m; token_no_default_policy: true; token_num_uses bounded (proposal: 16)
Rotation Nothing long-lived to rotate. The credential is a projected SA token (minted for at most 10m) exchanged for a 15m OpenBao token.
Revocation Platform removes the role binding or the policy (CCR deactivation). Deleting the SA also revokes. Revoke outstanding tokens by accessor. The admission expiry is enforced by the executor runtime and is not OpenBao authority.
Dormancy (founder decision) (a) The role exists only during an admitted window: platform applies it at admission and removes it after the receipt. Recommended for the pilot. (b) A standing role whose use is gated only by the admission record.
Evidence Lane id, admission id, actor (SA), exact paths, KV version before and after, accessor fingerprint, pass/fail booleans. Never values.

The svc-authelia ESO reader role (net-kingdom-svc-authelia-bind-eso, CCR-0053) stays unchanged and separate.

Question 2: directory credential to set svc-authelia's password in LLDAP

Answer: secrets-engine can catalog either shape. It recommends a shape that needs no new privileged account and keeps the dedicated account as a fallback.

Preferred: self-rotation with the current bind credential (no new LLDAP account)

The executor already reads the current svc-authelia value (version n) under Q1. It can log in to LLDAP as svc-authelia with that value and change that account's own password. It then writes the new value as version n+1 (CAS). Revert follows the same path in reverse: change the password back using the new value, and write the old value as n+2.

  • No lldap_password_manager membership and no new standing credential. The blast radius is the one account being rotated.
  • No extra secrets-engine lane. Q1's read+update policy covers the whole flow.
  • Must be proven first (net-kingdom / LLDAP deployment owner): on a synthetic LLDAP fixture, a bind user such as svc-authelia must be able to log in and change its own password, for example when it is in lldap_strict_readonly. Account lockout and rate limits must not break revert. Until this is proven, the shape is a hypothesis.

Fallback: dedicated LLDAP executor account as a cataloged credential

Use this if self-rotation is not possible.

Item Proposal
LLDAP account svc-nk-bind-executor, member of lldap_password_manager only. This can reset passwords of non-admin users, which includes every service bind, so the risk is high.
Catalog id nk-bind-executor-lldap-credential (kind kv, stage prod, risk high, approval ccr plus founder)
KV path platform/workloads/net-kingdom/directory-binds/svc-nk-bind-executor, field LDAP_BIND_PASSWORD
Access Added to the Q1 executor policy as ["read"] on that data path. There is no metadata read and no other reader. ESO does not project it, and it lives only in executor memory.
Rotation After each run, the executor changes its own LLDAP password and writes it with CAS. This needs update on its own path too. Otherwise the founder rotates it attended with the existing bind-lane setup pattern. The founder chooses.
Revocation Remove the account from lldap_password_manager or delete the account, revoke the KV read in the policy, and destroy the KV versions (platform).
Residual risk A compromised executor token within 15m can reset any non-admin LLDAP user. This is the main reason the self-rotation shape is preferred.

Items needing the founder

  1. Approve the Q1 lane shape and the dormancy option (a) or (b).
  2. Choose the Q2 shape: self-rotation, after the fixture proof, or the fallback account with its rotation mode.
  3. Approve SECRETS-WP-0017. Its catalog entries stay unapplied until the platform CCR exists and is approved.

Items for other owners

  • railiance-platform: a CCR request type for a Kubernetes-auth CAS read+update lane, cas_required=true on the svc-authelia metadata, the role and policy above, and the deactivation procedure.
  • net-kingdom: the LLDAP self-password-change proof on a synthetic fixture. The executor runtime must self-revoke and must refuse to run outside the admission window.