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:
- Creating a vault with a
VERCEL_API_KEYsecret, allowed domainapi.vercel.com. - Uploading the skill at Settings → Artifacts → Skills.
- 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
- Open Settings → Artifacts.
- Click Create Vault.
- Name — required, e.g. "Production". Up to 255 characters.
- Description — optional. A note for your future self about what this vault is for.
- 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.
| Field | Required | Notes |
|---|---|---|
| Environment Variable Name | yes | The name the agent will reference, e.g. HUBSPOT_API_KEY. Convention is uppercase with underscores. |
| Value | yes | The secret itself. Multiline is fine (useful for PEM-formatted keys). |
| Allowed Domains | optional but strongly recommended | Comma-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
| Secret | Allowed domains |
|---|---|
ANTHROPIC_API_KEY | api.anthropic.com |
OPENAI_API_KEY | api.openai.com |
GITHUB_TOKEN | api.github.com, github.com |
STRIPE_SECRET_KEY | api.stripe.com |
LINEAR_API_KEY | api.linear.app |
HUBSPOT_API_KEY | api.hubapi.com |
SLACK_BOT_TOKEN | slack.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.
- Open Fleet and click the agent.
- Scroll to Secret Vaults on the Configuration tab.
- 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.
- 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/deploymentsThe 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.
Related
- How Nairi manages secrets — the full security model
- Adding secrets to an agent
- MCP Tools — for credentials used by MCP servers (different path, no vault)
- Security at Nairi
Can't find what you're looking for? Email support@nairi.ai.