Skip to content

How secrets are handled

Secret values are write-only. You can set them and rotate them. Nothing reads one back — not a page, not an endpoint, not a log, not an audit row, not an error message, not an export.

This includes reading them back to you. It is not an access-control setting, and there is no administrator who can turn it off.

In the shared pure code, applied in two places: in the agent before anything is serialised onto the wire, and again on the server.

That ordering is the point. A compromised Seylo server cannot ask an agent for a Secret value, because the agent strips it before it ever becomes a message.

Key names, always. An environment variable sourced from a Secret shows the Secret and the key it comes from, so you can tell what a workload consumes without seeing what it consumes.

In the resource browser, Secrets are listed through the API server’s metadata-only content negotiation, and any value is stripped in shared code before it could be serialised.

Values can be set and rotated through the normal propose-and-approve flow. On the way:

  • A typed value is AES-256-GCM encrypted into the approval payload.
  • It is decrypted in memory at apply time.
  • The ciphertext is scrubbed from the request afterwards.
  • The manifest version, the git export and the audit log record key names with a withheld placeholder — never the value.

A canary check in our test suite greps every database table for a known test value, in plaintext and base64, and requires zero hits. It runs on every build.

The one place RBAC, not code, is the boundary

Section titled “The one place RBAC, not code, is the boundary”

If you enable the resource browser’s generic read in wildcard mode, the agent’s ServiceAccount becomes able to read Secrets at the Kubernetes API level. Seylo’s refusal to expose values is still enforced in code — but it is code, not RBAC.

The implication, stated plainly: anyone able to replace the agent’s image could read every Secret in the cluster with that token.

If that is in your threat model, use enumerated mode instead. It grants the core group without secrets, so Kubernetes itself makes the read impossible. The cost is that a CRD group must be listed before it can be browsed. See choose an RBAC posture.

Streamed to your browser and stored nowhere — no table, no manifest version, no operation event, no audit detail.

The audit trail records who read which pod’s logs, with which options, never the content.

Application logs routinely contain credentials the application printed. Seylo does not persist them; retain them in your cluster’s own log pipeline where your retention and access rules apply.

When Seylo exposes tools to a coding agent, no tool accepts a Secret value as an argument. A tool argument is a transcript entry, and a transcript is readable, forwardable and often retained by a third party. Accepting a secret value as an argument discloses it as thoroughly as returning one would.

Instead, a tool requests that a secret be supplied through the approval flow, where the value goes to the cluster and to nowhere else.

Not implemented, and not a gap we intend to fill. Among other reasons: a shell in a container reads Secret values trivially, and no amount of policy above it changes that. No route, no agent command, and no RBAC rule our chart can produce grants pods/exec or pods/attach at any setting.