Secrets - kubed-io/selenium-flow GitHub Wiki

Secrets

A secret is a named set of keys โ€” nextcloud with username and password, say โ€” that an operator put on the server. A caller can use one and can never see one. No tool, resource or report returns a value.

That is the whole point. A password an agent holds is in its transcript, its tool call, and whatever its host logs. A password it merely names is in none of them.

Putting secrets on the server

Set SECRETS_DIRS to a directory โ€” or several, separated like PATH. Inside, one directory per secret and one file per key, which is exactly the shape Kubernetes mounts a Secret in:

/secrets/
โ””โ”€โ”€ nextcloud/
    โ”œโ”€โ”€ username
    โ”œโ”€โ”€ password
    โ””โ”€โ”€ .meta.yaml        # optional

The file name is the key and the file's contents are the value. .meta.yaml describes the secret without changing it:

description: Admin login for the homelab Nextcloud
allowed_urls:
- https://nextcloud.example.com

Unset SECRETS_DIRS means the feature is off, and secret://secrets says so rather than returning an empty list that looks like an empty catalogue.

What a caller sees

The secret://secrets resource returns names, keys and sites. Never values.

Field Means
keys what may be named as key
allowed_urls the only sites it may be typed on, as exact origins
restricted: false no sites declared: usable anywhere
allowed_urls_rejected its site list is broken, so it cannot be used at all until an operator fixes it

Binding one

Give write a secret instead of text:

write(css="#password", secret={"name": "nextcloud", "key": "password"})

The result carries "text_from": "secret" and no value. The same argument goes in a flow step's args โ€” see Flows โ€” where the step's line in the report reads text=<hidden>.

Five rules, each refused rather than guessed at:

  • Only write takes a secret, and the rule is structural rather than written down: no other action has a secret argument, so there is nowhere to put one. It is the action that types a value into a field and does nothing else with it.

  • A secret is never part of a string. Flow parameters are written ${name} into any argument; a secret is not, and could not be. So no flow can send one somewhere by writing it into a URL or a script โ€” a secret reaches exactly one place, the field it is typed into.

    That is not the same as the value being safe once typed, and the difference is worth knowing. A write with submit: true can land the browser on ?q=<what was typed>, which is why the server scrubs a typed secret out of every report and error and refuses to store that page as somewhere to return to. See What this does not protect.

  • A secret's name may not come from a parameter. secret: {name: ${which}} is refused: choosing which credential gets typed is not a decision a caller's parameters may make.

  • Never text as well. Two values, one field, and picking one would be a guess that is wrong silently.

  • Navigate first, in its own step. A write binding a secret may not also take a url, because the site check reads the page the browser is on at the moment of typing โ€” a write that navigated would be checked against the page it was leaving.

Allowed sites

A restricted secret is typed only when the browser is on one of its allowed_urls, compared as an exact origin: scheme, host and port. https://nextcloud.example.com.evil.test is not a match, and neither is plain http://. A refusal names the page the browser was on and the sites it would have accepted.

Secrets in the config

The config file's secrets.entries is a second source, merged over what secrets.dirs collects โ€” not a replacement. It can add a description or a leash to a directory's secret, add or replace one of its keys, or define a whole secret with no directory behind it at all. See Configuration for the file itself.

Field If the config sets it If it does not
description replaces the directory's the directory's, if any
allowed_urls replaces the directory's leash entirely, a broken line included the directory's leash, if any
keys added; a key with the same name as a directory file replaces it for this key the directory's keys

A key reference is exactly one of three kinds:

keys:
  password: {file: /run/secrets/nextcloud/password}
keys:
  token: {env: AUTH_TOKEN}
keys:
  username: {value: demo}

The value is read at the moment it is bound, never cached: an env: key reads the environment then, a file: key reads the file then.

The Secrets tab shows three warnings:

  • inline value โ€” one of the secret's keys is {value: โ€ฆ}, written into the config file itself rather than read from somewhere else.
  • key unresolved โ€” an {env: โ€ฆ} variable is unset, or a {file: โ€ฆ} is missing, right now. The secret stays in the catalogue โ€” Kubernetes projects secrets asynchronously โ€” and binding that key refuses with the reason.
  • a broken leash โ€” a directory's _allowed_urls file has a line that does not parse as a bare origin. The secret cannot be used anywhere until it is fixed. A config-declared allowed_urls cannot end up here: an unparseable line there stops the server at boot instead.

Prefer file: or env:; value: writes the secret into the config file itself.

A parameter or a secret?

A parameter is for what varies between runs; a secret is for what must not be seen. An email address is a parameter. Its password is a secret.


Flows ยท write ยท Deployment

โš ๏ธ **GitHub.com Fallback** โš ๏ธ