Skip to content

Store a secret

View as Markdown

This guide stores, replaces and lists your tenant's secrets with kindgi secrets, without a value going through your shell's history or a command line.

Tools' declared secrets, HTTP tools' credentials, model providers' keys and MCP endpoints' credentials are all secrets of your tenant. Each is looked up by name in an environment.

  • A runtime, such as kindgi dev, with Kindgi 0.1's CLI.
  • openssl, to make a key for the examples.

A secret belongs to an environment and a scope. Set it, and type the value when it asks:

Terminal window
pnpm exec kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant
Value:
Re-enter to confirm:

It prompts twice, without echoing, then prints the secret's name, scope, environment and version as JSON, and Set RECEIPT_SIGNING_KEY at tenant in local.

  • RECEIPT_SIGNING_KEY is the secret's name, as a tool declares it. A new name uses only ASCII letters, digits, ., - and _, starts with a letter, digit or _, doesn't end with . or have two . in a row, and is at most 255 characters long; set refuses one that doesn't (secret-name-invalid). Under kindgi dev, the rule is narrower.
  • --env is the environment the secret belongs to. A runtime resolves secrets in the environment it serves, which KINDGI_ENV names. kindgi dev serves local.
  • --scope is where it lives: tenant, org:<orgId> or project:<projectId>. It's required.

In a script, pipe the value in with --from-stdin. Or read it from a file only you can read, with --from-file=<path>: a file others can read is refused. Here openssl rand -hex 32 | tr -d '\n' makes a 64-character key, without a newline:

Terminal window
openssl rand -hex 32 | tr -d '\n' | pnpm exec kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdin
…
Set RECEIPT_SIGNING_KEY at tenant in local.
Excerpt

The secret is available to the next call. Nothing restarts.

set refuses a name that exists:

Version conflict: RECEIPT_SIGNING_KEY already exists (version 1). To store a new version, retry with --write-mode=add-version.

Write a new value with --write-mode=add-version:

Terminal window
openssl rand -hex 32 | tr -d '\n' | pnpm exec kindgi secrets set RECEIPT_SIGNING_KEY --env=local --scope=tenant --from-stdin --write-mode=add-version

It prints the JSON, with the new versionId, and the same Set RECEIPT_SIGNING_KEY at tenant in local. line.

--if-version=<n> makes the write conditional: it fails if someone changed the secret since version n.

list and get show names and versions, never values. Get one by its name, environment and scope:

Terminal window
pnpm exec kindgi secrets get RECEIPT_SIGNING_KEY --env=local --scope=tenant
{
"name": "RECEIPT_SIGNING_KEY",
"scope": {
"kind": "tenant",
"tenantId": "bb22c936-5111-429a-bfce-09650af85492"
},
"envName": "local",
"currentVersion": 1,
"createdAt": "1970-01-01T00:00:00.000Z",
"updatedAt": "1970-01-01T00:00:00.000Z"
}

kindgi secrets list --env=local --scope=tenant lists the environment's secrets by name, 25 to a page (--limit takes up to 100). While more remain, the page has a nextCursor: pass it as --cursor for the next page. --include-revoked lists revoked secrets too, with their revokedAt and revokeReason. Paging and --include-revoked need a runtime of 0.1.8 or later.

A tenant admin lists the environments with GET /v1/environments: each env name that holds an env value or a secret, at any scope, once, in byte order. A revoked secret doesn't count.

kindgi dev's secrets store is the pack's env files: your app's, and Kindgi's own. Keep local values in env files describes them. So the store behaves like them:

  • set writes the value to Kindgi's own .kindgi/secrets.env, readable only by you, which your app doesn't load. With --app, it writes your app's own env file instead, for a value your app reads too.
  • Every name in the env files is a secret of local, and list shows them all. Their timestamps are the epoch, as in get's answer.
  • Its environments are local and each .env.<name> file, each once it holds a name. GET /v1/environments lists those.
  • A name has one value: replacing it with add-version overwrites it, and its version stays 1.
  • The files are the same for every scope, so --scope doesn't separate anything here.
  • It refuses what an env file can't hold as given: a name that isn't capital letters, digits and underscores, starts with a digit, or is KINDGI_* (secret-name-invalid; a kindgi. name gets reserved-name-prefix, as in every store), and a value no env-file quoting can hold so that it reads back unchanged (secret-value-invalid). Each message says why. Store such a value encoded (base64, say).
  • There's nothing to rotate or revoke. Those commands say so:
Error [secret-operation-unsupported]: Dev secrets live in your env files (.env, .env.local, .kindgi/secrets.env) and have no versions to rotate. Edit the value there, or run `kindgi secrets set RECEIPT_SIGNING_KEY --write-mode=add-version`.
Error [secret-operation-unsupported]: Dev secrets live in your env files (.env, .env.local, .kindgi/secrets.env) and have no revocation. Remove HTTPBIN_TOKEN from those files.

Versions, scopes, rotation and revocation are what a deployment's secrets store adds. That store is Postgres, with KINDGI_SECRETS_BACKEND=postgres, or your own secret manager. The environment variable reference has the setting. Every flag is in the kindgi secrets reference.