Vaults & Secrets

Vaults & Secrets

Org-level encrypted key-value storage for credentials, with safe runtime injection.

Vaults are where you store anything sensitive your agents need: API keys, database passwords, OAuth tokens, webhook signing secrets. Values are encrypted at rest, hidden from the dashboard, and injected at the network layer instead of the filesystem so they never end up in a log file or a process memory dump.

For the encryption and injection details, see How Nairi manages secrets. This page is the practical setup guide.

Vaults are a managed-runtime feature. Self-hosted agents don't have a secret proxy and can't attach vaults. Use plain environment variables or your own secret store on self-hosted runtimes.

Mental model

  • A vault is a named bundle of secrets. You group related credentials together: "Production", "HubSpot creds", "Stripe test keys".
  • A secret has an env-var name, a value, and an allowed-domains list.
  • Vaults live at the org level. Attach them to specific agents from the agent editor.
  • At runtime, the agent sees a placeholder (e.g. CCASECRET_HUBSPOT_API_KEY) in its environment. The real value is swapped in over the wire when the agent makes an outbound HTTPS request to one of the allowed domains.

Best paired with skills

The canonical use case for a vault: a skill that talks to a third-party API, with the API key held in a vault.

Say you've packaged a skill called vercel-deploy that triggers Vercel deployments. The skill's script just reads $CCASECRET_VERCEL_API_KEY and curls the Vercel API. You wire it together by:

  1. Creating a vault with a VERCEL_API_KEY secret, allowed domain api.vercel.com.
  2. Uploading the skill at Settings → Artifacts → Skills.
  3. Attaching both the vault and the skill to the same agent.

Anywhere the skill (or the agent itself) sends a request to api.vercel.com, the proxy injects the real key. Anywhere else, it sees the placeholder.

This pattern works for any API the agent should be able to call: Render, Stripe, Linear, GitHub, internal services. One skill that knows how to call the API, one vault secret that authenticates it.

Step 1 — Create a vault

  1. Open Settings → Artifacts.
  2. Click Create Vault.
  3. Name — required, e.g. "Production". Up to 255 characters.
  4. Description — optional. A note for your future self about what this vault is for.
  5. Click Create.

The vault appears in the list with "0 secrets" next to it.

Step 2 — Add secrets to the vault

Click the vault's row to open the Manage Vault dialog. Scroll to the Add Secret form.

FieldRequiredNotes
Environment Variable NameyesThe name the agent will reference, e.g. HUBSPOT_API_KEY. Convention is uppercase with underscores.
ValueyesThe secret itself. Multiline is fine (useful for PEM-formatted keys).
Allowed Domainsoptional but strongly recommendedComma-separated list of domains where this secret is allowed to be injected, e.g. api.hubapi.com. Wildcards like *.example.com are supported. Leave blank to allow any domain (not recommended).

Click Add Secret. The new secret appears in the list above.

Common allowed-domain values

SecretAllowed domains
ANTHROPIC_API_KEYapi.anthropic.com
OPENAI_API_KEYapi.openai.com
GITHUB_TOKENapi.github.com, github.com
STRIPE_SECRET_KEYapi.stripe.com
LINEAR_API_KEYapi.linear.app
HUBSPOT_API_KEYapi.hubapi.com
SLACK_BOT_TOKENslack.com

The narrower the list, the smaller the blast radius if anything goes wrong. See security model for why this matters.

Step 3 — Attach the vault to an agent

The vault doesn't reach any agent until you attach it.

  1. Open Fleet and click the agent.
  2. Scroll to Secret Vaults on the Configuration tab.
  3. Tick the checkbox next to the vault you just created. Each row shows the vault's name and a small badge like "3 secrets" so you can confirm you're picking the right one.
  4. Click Save & Redeploy at the bottom-right.

The agent's container is rolled out, the proxy fetches the new secret list, and the agent can now use the placeholders.

Step 4 — Reference the secret

Use the env-var name you set, prefixed with CCASECRET_. The agent sees this placeholder string verbatim. The real value gets swapped in by the secret proxy on outbound HTTPS calls to one of the allowed domains.

From a skill

The most common pattern. A skill's helper script reads the env var and makes the API call:

# scripts/trigger-deploy.sh inside a `vercel-deploy` skill
curl -X POST https://api.vercel.com/v13/deployments \
  -H "Authorization: Bearer $CCASECRET_VERCEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"name\": \"$PROJECT_NAME\", \"target\": \"production\"}"

The skill author doesn't need to know anything about vaults — they write the script assuming the env var is set. The operator (you) wires up the vault with VERCEL_API_KEY and an allowed domain of api.vercel.com. Same skill works for everyone, secrets stay per-org.

From a shell command the agent runs ad-hoc

If the agent decides to call an API directly rather than going through a skill (e.g. "check our Vercel deployment status"), the same placeholder works from any shell command it runs:

curl -H "Authorization: Bearer $CCASECRET_VERCEL_API_KEY" \
  https://api.vercel.com/v2/deployments

The literal string CCASECRET_VERCEL_API_KEY is what ends up in the agent's memory and any logs. The real key only ever exists on the wire, briefly, on a request to api.vercel.com.

Vault secrets are not for MCP credentials. MCP configs are hidden from the agent (they live in the mcp-proxy sidecar), so credentials needed by an MCP server should be inlined directly in the MCP JSON. See Credentials in MCP configs.

Rotating a secret

You don't need to redeploy to rotate. Open the vault, find the secret, click the edit icon (pencil), paste the new value, click Save. The secret proxy refreshes its cache every two minutes, so the new value is live within that window.

If you need it instant: redeploy the agent. The new container picks up the latest secrets on boot.

Updating allowed domains

Same flow as updating the value. Open the secret, change the domains field, save. The change takes effect on the proxy's next refresh.

Deleting a secret

In the vault's manage dialog, find the secret, click the trash icon. A confirmation dialog asks you to confirm by typing the secret's name.

The deletion takes effect within ~2 minutes (or immediately on the next redeploy). Any code still referencing the placeholder after the secret is gone will see the literal CCASECRET_<NAME> string on the wire.

What about non-sensitive config?

Use Environment Variables on the agent itself, not a vault. They're meant for things like GITHUB_DEFAULT_BRANCH=main or API_BASE_URL=https://.... Plaintext, not domain-restricted, visible in the dashboard. See the agent editor walkthrough.


Can't find what you're looking for? Email support@nairi.ai.

On this page