TUTORIAL

Protect AI Secrets

Store real provider secrets in Project Secrets and use placeholders inside managed boxes.

Use Project Secrets before you run SDKs, scripts, or coding agents inside boxes that need upstream AI access.

Project Secrets let you call AI providers without putting the real API key in a box. Save the real key in Portal, put the placeholder in the box, and keep using the provider’s normal API URL.

Portal Project Secret
  real key:    sk-real-provider-secret
  placeholder: run9secret_abcd1234

Managed box
  OPENAI_API_KEY=run9secret_abcd1234
        |
        v
Request to api.openai.com
  Authorization: Bearer run9secret_abcd1234
        |
        v
run9 egress replaces the placeholder
        |
        v
Provider sees the real key

No replacement happens in normal boxes, or when the request does not match the configured host and header.

Create a Project Secret

Project admins can create project-scoped secrets that work in every managed box in the project. Project members can create box-scoped secrets for a specific box.

Create the rule from your terminal. The command prints the generated Placeholder; use that placeholder inside managed boxes.

printf '%s' "$REAL_PROVIDER_SECRET" | sys9 run project secrets create \
  --name provider-name \
  --value-file - \
  --allowed-host api.provider.example \
  --header-name Authorization

Use sys9 run project secrets ls to list existing rules, sys9 run project secrets update <secret-id> to replace the value or rule metadata, and sys9 run project secrets rm <secret-id> to delete one.

To scope the rule to one box, create a Box Secret for that box:

printf '%s' "$REAL_PROVIDER_SECRET" | sys9 run box secrets create ai-box \
  --name provider-name \
  --value-file - \
  --allowed-host api.provider.example \
  --header-name Authorization

Use sys9 run box secrets ls ai-box to list only that box’s scoped rules. You can also create project-scoped rules in Portal from Project Settings -> Secrets, or box-scoped rules from a Portal Box Detail page’s Secrets tab.

V1 uses custom rules only. There are no provider presets: choose the domain and header rule yourself.

Use a Managed box

Project Secret substitution only runs for boxes with Network = Managed.

When you create a box from the CLI, pass --network managed:

sys9 run box create ai-box --network managed

In Portal, choose Managed in the Network field. If an existing box is still Normal, change it to Managed, then start a new exec so run9 creates a new managed instance.

OpenAI-compatible clients

Create a Project Secret:

printf '%s' "$REAL_OPENAI_API_KEY" | sys9 run project secrets create \
  --name openai \
  --value-file - \
  --allowed-host api.openai.com \
  --header-name Authorization

Inside a managed box:

export OPENAI_API_KEY=<project-secret-placeholder>

Keep the normal OpenAI base URL. The client builds Authorization: Bearer <project-secret-placeholder>, and run9 replaces only the placeholder part before the request leaves the box.

Anthropic-compatible clients

Create a Project Secret:

printf '%s' "$REAL_ANTHROPIC_API_KEY" | sys9 run project secrets create \
  --name anthropic \
  --value-file - \
  --allowed-host api.anthropic.com \
  --header-name X-Api-Key

Inside a managed box:

export ANTHROPIC_API_KEY=<project-secret-placeholder>

Keep the normal Anthropic API endpoint. run9 replaces the placeholder in X-Api-Key only when the request host matches api.anthropic.com.

First checks when requests fail

Check these things before changing client code:

  • the box is using Network = Managed
  • the request goes to a host listed in Allowed Hosts
  • the client sends the placeholder in the configured Header Name
  • the configured header value contains the placeholder
  • the client is not using QUIC, HTTP/3, mTLS, or certificate pinning

Why this is safer

  • the real provider secret stays in project settings instead of box storage
  • box-scoped secrets only apply to the selected box
  • each project controls exactly which hosts and headers can receive the secret
  • forking a box or snap does not copy the real provider secret
  • normal boxes keep ordinary network behavior and do not run Project Secret substitution