> ## Documentation Index
> Fetch the complete documentation index at: https://keel-cloud.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets

> How a secret value travels from the form to the run — encrypted at rest, masked in logs, never echoed back — and what that does and does not protect.

Mark any credential, token, or key as a secret:

```yaml theme={null}
variables:
  GCP_SERVICE_ACCOUNT_KEY:
    label: Service account key (JSON)
    type: multiline
    secret: true
```

## What Keel does with a secret

**1. In the form**

Secret fields render as password inputs — including multi-line ones,
which are masked while you type. A field whose target already has a
saved value shows a *saved — leave blank to keep* placeholder; submit it
blank and the value stays, type something and it is replaced. The saved
value itself is never sent to the browser.

**2. At rest**

Values are encrypted with AES-256-GCM before they are written. In Keel
Dev the key is `dev.key` in the user's config directory
(`~/Library/Application Support/keel/`, `~/.config/keel/`, or
`%AppData%\keel\`), created on first use. In Keel Cloud it is
`KEEL_ENCRYPTION_KEY`, or a generated file in `KEEL_DATA_DIR` when unset.
Non-secret values are encrypted the same way; the secret flag governs
display and logging.

**3. In the run**

The value is exported as a plain environment variable inside the
container, exactly like any other. Steps read it as `$NAME`. Nothing
about the container is special; a step could print it. Do not.

**4. In the log**

Every log line is scanned for every secret value before it is stored or
displayed, and matches are replaced with `•••`. This catches a step that
prints a credential and any tool that echoes it. It works on exact
substrings: a transformed value — base64-encoded, URL-escaped, split
across lines — is not recognized.

**5. In outputs**

An output whose value contains a secret input's value is treated as
secret automatically. An output that shares a secret variable's name must
declare `secret: true`. Secret outputs are stored encrypted and shown
masked behind a reveal control; `keel deploy` never prints them.

## Constraints

* Secrets cannot declare a `default`.
* `boolean` and `select` variables cannot be secret — their values are not
  the kind of thing you hide.
* Validation, deploy-time, conditions, and layout all apply to secrets as
  they do to other variables.

## Rotating a secret

Open the target, type the new value into the field, save. The old ciphertext
is replaced. Runs that already finished keep their logs, with the old value
masked wherever it appeared.

## Rotating the encryption key

Not supported: values encrypted with the old key become unreadable. If you
must change the key, note every value, change the key, and re-enter them.
Back up `KEEL_ENCRYPTION_KEY` (or `dev.key`) with the same care as the
database.

## What secrets do not protect against

Deployment steps are arbitrary code from the repository, executed with the
target's values on the Keel host. Anyone who can change `keel.yaml` or the
scripts it calls can read every value the deployment receives. Treat the
repository — and in Keel Cloud, the **configure** scope and the host itself
— as part of the trust boundary. Keel Cloud additionally limits who can see
secret outputs to members with the deploy or configure scope.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.