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

# Secrets

> Store API tokens and credentials as encrypted, org-level secrets, and inject them into batch jobs as environment variables.

A **secret** is an encrypted, organization-scoped credential — an API token, password, database URL, or any other sensitive string. Use secrets instead of pasting plaintext into commands, image configs, or repo files. At runtime, VESSL Cloud injects the secret into your container as an environment variable. The value is encrypted on your machine before it's sent, kept out of request bodies and access logs, and stored only as ciphertext.

<Note>
  Anyone in the organization can view secrets, create new ones, and reference a secret by name when creating a batch job. Updating or deleting a secret requires the **Organization admin** role — see [Manage secrets](/admin/secrets/overview).
</Note>

<Info>
  VESSL Cloud has completed a **SOC 2 Type II** security attestation. See [trust.vessl.ai](https://trust.vessl.ai) for the full report and our security posture.
</Info>

<div>
  <Frame>
    <img src="https://mintcdn.com/dora/ak9sJWQAzmPhmU9G/images/secrets-list-member.png?fit=max&auto=format&n=ak9sJWQAzmPhmU9G&q=85&s=febf9374a7119a42faf3efa6bcca9ceb" alt="Secrets page with a table of secrets showing Secret Name, Key, masked Value, Slug, Last edited by, and Edited at columns, plus a New Secret button" width="3360" height="2040" data-path="images/secrets-list-member.png" />
  </Frame>

  <small>Example: Secrets page as a member sees it — no edit or delete menu on the rows</small>
</div>

## Common use cases

| Env var             | Used for                   |
| ------------------- | -------------------------- |
| `HF_TOKEN`          | Hugging Face               |
| `OPENAI_API_KEY`    | OpenAI                     |
| `ANTHROPIC_API_KEY` | Anthropic                  |
| `WANDB_API_KEY`     | Weights & Biases           |
| `GITHUB_TOKEN`      | GitHub                     |
| `DATABASE_URL`      | Database connection string |

## How it works

* **Encrypted before it leaves your machine** — when you create a secret, the value is sealed with your organization's public key locally (libsodium sealed-box), so the plaintext never appears in request bodies or access logs. VESSL Cloud re-encrypts it at rest with a master key and stores only the ciphertext.
* **Injected at submission time** — when you submit a workload, VESSL Cloud decrypts the value server-side and delivers it to your container as a Kubernetes Secret, surfaced as an environment variable when your container starts.
* **Write-only values** — after a secret is saved, VESSL Cloud never shows its value again to anyone, member or admin; the list and detail views show only metadata. To change a value, an admin rotates it by overwriting it with a new one — the previous value can't be retrieved.
* **Organization-scoped** — secrets are shared across all teams in the organization. Every batch job in the org can reference any secret by name.
* **Open to create, admin-gated to change** — anyone in the organization can view secrets and create new ones. Only **Organization admin** can [update or delete](/admin/secrets/overview) a secret, including secrets that members created; members don't see the edit and delete controls on the secrets list.

## Create a secret

A secret has three core fields:

| Field           | What it is                                                                                                                                |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Secret name** | Your identifier for the secret. Unique per organization.                                                                                  |
| **Key**         | The default env var name when the secret is injected into a workload. Must match `^[A-Za-z_][A-Za-z0-9_]*$` (env-var format, ≤256 chars). |
| **Value**       | The plaintext credential. Encrypted before it leaves your machine.                                                                        |

Keep **Secret name** and **Key** identical (`HF_TOKEN`/`HF_TOKEN`) for simplicity, or use a different **Secret name** when you need multiple secrets that share the same env var — for example `hf-prod` and `hf-staging`, both with key `HF_TOKEN`.

### GUI

1. In the sidebar, select **Settings**.
2. Select **Secrets** under **Account**.
3. Click **New Secret**.
4. Fill in **Secret name**, **Key**, and **Value**.
5. Click **Create**.

<div>
  <Frame>
    <img src="https://mintcdn.com/dora/ak9sJWQAzmPhmU9G/images/secrets-create-modal.png?fit=max&auto=format&n=ak9sJWQAzmPhmU9G&q=85&s=d7766e70b71f4677914bacdfe9acce85" alt="Create new Secret modal with Secret name, Key, and Value fields, plus Cancel and Create buttons" width="3840" height="2488" data-path="images/secrets-create-modal.png" />
  </Frame>

  <small>Example: new secret modal</small>
</div>

### CLI

```bash theme={null}
# Interactive masked prompt (when stdin is a TTY)
vesslctl secret create HF_TOKEN HF_TOKEN

# Read the value from an env var
vesslctl secret create HF_TOKEN HF_TOKEN --from-env LOCAL_HF_TOKEN

# Read from stdin
echo "$HF_TOKEN" | vesslctl secret create HF_TOKEN HF_TOKEN --from-stdin

# Add a description
vesslctl secret create HF_TOKEN HF_TOKEN -d "Hugging Face token (prod)"
```

The plaintext value never appears on the command line — `--from-env` and `--from-stdin` keep it out of your shell history.

## Use a secret in a job

### GUI

In the **Environment variables** section of the job-create form, pick a secret from the **Secrets** dropdown. Click **Add secret** to attach more. Plain variables and secrets coexist, but if a plain variable uses the same env-var key as a secret, the plain variable's value takes precedence.

<div>
  <Frame>
    <img src="https://mintcdn.com/dora/JNAR1GfyPwQhmXIo/images/secrets-job-injection.png?fit=max&auto=format&n=JNAR1GfyPwQhmXIo&q=85&s=f7ffb28b79020408308f5d8798c64de5" alt="Environment variables section of the job-create form with a Secrets dropdown, an Add secret button, and a Variables table for plain key-value pairs" width="701" height="380" data-path="images/secrets-job-injection.png" />
  </Frame>

  <small>Example: linking a secret on the job-create form</small>
</div>

### CLI

Inject one or more secrets into a batch job with `--secret`:

```bash theme={null}
# Inject as env var HF_TOKEN, referencing the secret named HF_TOKEN
vesslctl job create ... --secret HF_TOKEN

# Inject as env var OPENAI_API_KEY, referencing the secret named openai-prod
vesslctl job create ... --secret OPENAI_API_KEY=openai-prod

# Multiple secrets
vesslctl job create ... --secret HF_TOKEN --secret OPENAI_API_KEY
```

* `--secret NAME` injects the secret as an env var with the same name.
* `--secret KEY=NAME` injects the secret as env var `KEY`, referencing the secret named `NAME`.
* A key can't appear in both `--env` and `--secret` — the CLI rejects the command, so pick one flag per env var.

<Note>
  Workspaces don't support secret injection yet. Secrets ship for jobs today; workspace support is on the roadmap.
</Note>

## List secrets

```bash theme={null}
# List active secrets
vesslctl secret list

# Include soft-deleted entries
vesslctl secret list --include-deleted
```

Updating and deleting secrets is admin-only — see [Manage secrets](/admin/secrets/overview).

## FAQ

<AccordionGroup>
  <Accordion title="Who can manage secrets?">
    Anyone in the organization can view secrets and create new ones. Updating or deleting a secret — including one you created yourself — requires the **Organization admin** role, so members don't see the edit and delete controls on the secrets list. Members can reference a secret by name when creating a batch job — they don't need admin access to use one. (A saved value can't be viewed again by anyone, member or admin; this isn't a member-only limit.)
  </Accordion>

  <Accordion title="How does VESSL Cloud protect my secret value?">
    The value is sealed with your organization's public key on your machine (libsodium sealed-box) before it's sent, so the plaintext never appears in request bodies or access logs. VESSL Cloud stores only the ciphertext — re-encrypted at rest with a master key — and decrypts it server-side only to inject it into your workload when you submit a job. Access is governed by our [SOC 2 Type II](https://trust.vessl.ai) controls.
  </Accordion>

  <Accordion title="Why are Secret name and Key separate fields?">
    **Secret name** is your identifier (unique per organization). **Key** is the env-var-shaped reference used by default when injecting into a workload. Keep them identical for simplicity (`HF_TOKEN`/`HF_TOKEN`), or use distinct names when you need multiple secrets that map to the same env var (for example, `hf-prod` and `hf-staging`, both with key `HF_TOKEN`).
  </Accordion>

  <Accordion title="What happens if --env and --secret use the same env-var key?">
    The CLI rejects the command — `vesslctl job create` errors when a key appears in both flags, so pick one per env var. In the GUI, the two can coexist: a plain variable with the same key as a secret takes precedence, and the secret reference is ignored.
  </Accordion>

  <Accordion title="Do running workloads see updated secret values?">
    No. Secrets are injected at container start. Restart the workload to pick up the new value.
  </Accordion>
</AccordionGroup>
