125 lines
7.7 KiB
Markdown
125 lines
7.7 KiB
Markdown
# Credential separation — reviewed change package
|
|
|
|
2026-09-28. Prepared under the existing CUST-WP-0073 tasks. The initial admission rollout was rolled back, then corrected and re-enabled; see the
|
|
[rollout receipt](../../evidence/2026-09-28-secret-annotation-rollout.md). The founder selected agent-specific supervised/autopilot modes in
|
|
[the decision record](../../agent-autonomy-decision.md). The concrete supervised
|
|
execution path and account cutover remain unimplemented.
|
|
|
|
## Verified current state
|
|
|
|
`ssh railiance01` runs as `tegwick` (uid 1000), with `(ALL) NOPASSWD: ALL`.
|
|
`/etc/rancher/k3s/k3s.yaml` is `644 root root`.
|
|
`kubectl auth whoami` reports `system:admin`, `system:masters`.
|
|
No credential contents were read. The public principal inventory in
|
|
`railiance-infra/ansible/inventory/ssh_principals.yaml` maps both `agt-*` and
|
|
`adm-full` to `tegwick`. ops-warden issues certificates; railiance-infra owns
|
|
host principal mapping. A different principal on this same account does not
|
|
separate privilege.
|
|
|
|
## Supervised starting identity and later scoped promotion (T01/T02)
|
|
|
|
Use separate agent and admin OS identities on both the workstation and server.
|
|
Agents must not inherit the admin SSH key/certificate, SSH agent socket, sudo,
|
|
container-runtime socket, kubeconfig, OpenBao token or admin home directory.
|
|
Moving a file or changing the default context under the same unrestricted
|
|
account is insufficient. Keep an independently verified attended admin session
|
|
open during cutover; verify recovery before withdrawing the old agent path.
|
|
|
|
The supervised starting Kubernetes identity is outside `system:masters`, with an
|
|
explicit reviewed observation allowlist. Do not simply bind built-in `view`:
|
|
ConfigMaps, pod specs and logs can themselves contain credentials. Do not grant
|
|
workload edits, arbitrary ConfigMap writes, exec/attach/portforward, proxy,
|
|
logs, Secret verbs, token issuance, impersonation, RBAC writes or CSR approval.
|
|
Broader action authority is a per-agent autopilot grant earned through evidence,
|
|
with cost and risk limits in EUR; it is not unrestricted credential access.
|
|
|
|
Deployment create/patch authority allows code or mounts to extract credentials.
|
|
This is an upstream documented escalation route, not a missing deny rule:
|
|
[Kubernetes RBAC good practices](https://kubernetes.io/docs/concepts/security/rbac-good-practices/).
|
|
Agents prepare exact changes; in supervised-mode the supervisor approves or runs
|
|
them through the privileged path. An agent-controlled GitOps write path must obey
|
|
that same gate. Later autopilot may execute scoped actions without individual
|
|
approval only through verified policy and budget/risk enforcement. Otherwise it
|
|
recreates the bypass. Mode, supervisor, proposal dispositions and verified
|
|
outcomes belong to the identified agent's existing records and receipts.
|
|
|
|
Set k3s's persistent kubeconfig mode to `600` in railiance-enablement and fix
|
|
the existing file, but do not mistake that step for OS-account separation.
|
|
The final selected launcher/account setup must prove agents cannot regain the
|
|
old admin account, including through workstation/Windows interoperability.
|
|
No new credential broker or harness implementation is proposed.
|
|
|
|
Acceptance uses the actual agent process/account, not only admin impersonation:
|
|
whoami without masters; denied Secret get/list/watch; denied pod exec, workload
|
|
writes, logs, token issuance and impersonation; denied admin-file reads and
|
|
sudo; no accessible admin socket/key/token; approved observation succeeds;
|
|
attended admin recovery succeeds. Record authorization booleans and file access
|
|
results, never credential contents. Negative checks must not attempt to print
|
|
an actual secret if access unexpectedly succeeds.
|
|
|
|
## Secret annotation policy (T03)
|
|
|
|
`reject-secret-last-applied.yaml` contains a native v1 policy and Deny binding.
|
|
It rejects the annotation key even when its value is empty, on CREATE/UPDATE,
|
|
cluster-wide. It introduces no controller or workload. Server dry-run on the
|
|
verified v1.35.1+k3s1 cluster accepted both objects on September 28:
|
|
|
|
```text
|
|
validatingadmissionpolicy.admissionregistration.k8s.io/reject-secret-last-applied serverside-applied (server dry run)
|
|
validatingadmissionpolicybinding.admissionregistration.k8s.io/reject-secret-last-applied serverside-applied (server dry run)
|
|
```
|
|
|
|
Subsequent live native tests passed, but actual ESO refresh failed and required
|
|
rollback. Enforcement is now enabled after explicit metadata fixes and successful fresh
|
|
refreshes of all 39 ExternalSecrets. The platform owner's pinned revision
|
|
`7daf7e9` is authoritative; the original proposal file is retained for history.
|
|
Reference: [ValidatingAdmissionPolicy](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/).
|
|
|
|
Before any retry, fix and verify the 31 ESO declarations described in the rollout
|
|
receipt, then in one attended railiance-platform window: remove existing last-applied
|
|
annotations without logging values; persist the manifest in that owner's
|
|
deployment path; dry-run and diff; install policy and binding. Use only a
|
|
synthetic, non-credential Secret in a scratch namespace to verify clean create
|
|
and update succeed, annotated create/update (including empty annotation) fail,
|
|
and client-side apply fails. Verify the policy type-check status, then remove
|
|
the fixture. Record only names, booleans and counts. Do not use dry-run output
|
|
of real Secret objects or print admission errors containing real values.
|
|
|
|
If the policy interrupts a required write, the attended admin can delete its
|
|
binding, fix the writer to use server-side apply/replace, and rebind. This
|
|
temporarily reopens annotation leakage and must be recorded. The policy does
|
|
not revoke any credential or stop other ways of reading secrets.
|
|
|
|
## Guidance and deferred rotation (T04/T05)
|
|
|
|
The September 24 standing notice exists. The raw presence template is now
|
|
withdrawn: absent annotations can trigger a dump of the full Secret. Use only
|
|
the maintenance helper, which captures and suppresses kubectl output on errors. Claude's recorded guard remains a
|
|
stopgap. No equivalent Codex/Grok read-denial hook has been established by this
|
|
work; this session has broad kubectl/SSH permissions, so instructions are the
|
|
current protection. No claim is made that every Grok installation was inspected.
|
|
OpenBao/Vault secret reads belong inside the same attended boundary, regardless
|
|
of preapproved command prefixes.
|
|
|
|
Rotation remains in existing T05 with the founder's September 24 trigger-based
|
|
deferral. Do not silently cancel it or open another plan. At final closure,
|
|
either execute the rotation in its attended window or explicitly resolve its
|
|
existing disposition under the work-record rules. No rotation was performed.
|
|
|
|
## Bounded implementation evidence
|
|
|
|
The existing sandbox mechanism passed the synthetic checks in
|
|
[the sandbox receipt](../../evidence/2026-09-28-supervised-sandbox-proof.json).
|
|
It does not prove interactive agent migration. The per-agent record at
|
|
`.kaizen/agents/custodian-codex/supervision.json` keeps this agent supervised,
|
|
with no autopilot grant or EUR limits assigned. The descriptive summarizer
|
|
`scripts/summarize_agent_supervision.py` cannot authorize or promote an agent.
|
|
No eligible scoring sample exists; the failed annotation rollout and recovery
|
|
are retained visibly rather than counted as unchanged success.
|
|
|
|
Current T03 outcome: nine admission checks pass; all 39 ExternalSecrets refreshed
|
|
successfully under Deny; the guard is Synced/Healthy. Source fixes and deployment
|
|
receipts are in the linked rollout record. The absent-namespace orphan Secret was deleted after explicit founder approval,
|
|
using its exact UID precondition; absence and unchanged 3 GiB PVC were verified.
|
|
`orphan-secret-deletion.json` now contains the execution disposition. T03 is
|
|
complete. Agent-runtime migration remains a separate unfinished task.
|