Skip to main content
Credential injection puts secrets on the network instead of in the Sailbox. You store an API key with Sail, write a policy that says which HTTPS host gets it, and attach the policy to a Sailbox. Code inside sends a normal request with no credential, and Sail adds it on the way out. The Sailbox, and any agent running on it, can use the API but can never read the key.

Try it

This stores a secret, injects it as a bearer token on requests to httpbin.org, and asks httpbin to echo the request back: Save the policy as demo.json:
demo.json
Then store the secret, create and attach the policy, and make a request from inside the Sailbox:
Output
The curl inside the Sailbox never saw the token. Only the request that reached httpbin carried it. The same flow from the SDKs, with a GitHub token:

Secrets

A secret is a named value that belongs to your organization.
Setting a name that already exists replaces its value. The next matching request from any Sailbox whose policy uses it gets the new value. Names start with a letter or digit and may contain letters, digits, _, and -, up to 128 characters. A value is one non-empty line of text up to 64 KiB, with no tabs, line breaks, or other control characters.

Policies

A policy is a JSON document that belongs to your organization. Each top-level key is a host, and each host has an ordered list of rules. Sail picks the most specific host entry for a request, then the first rule under it that matches, and applies that rule. If nothing matches, the request goes out unchanged.
Hosts. Write a bare hostname: no https://, port, or path. api.example.com matches exactly that host. *.example.com matches any direct subdomain, and * matches everything not named elsewhere. Use an exact host whenever a rule adds a credential: a wildcard sends the credential to every host it matches. Match. Leave match out to cover every request to the host; such a rule must be last in its list. Otherwise narrow by method (upper case, one or a list), path, headers, or query. Values accept a plain string for an exact match, {"prefix": "..."}, or {"one_of": [...]}; a header or query condition can also assert "present": false. What a rule does.
  • A forward host must be exact. If Sail cannot reach it, the request fails; it is not sent to the original host instead.
  • respond stops that HTTP request only. It is not a network access control; other traffic to the same host may still be possible.
  • request.set.headers and request.set.query are templates: every $ in them must be part of ${secrets.NAME} or $$ (a literal dollar sign). In every other string $ is plain text, except that an unescaped ${ is rejected because it looks like an unresolved reference.
  • The secret a policy names must exist before the policy is created.
  • An invalid document fails at create time with an error naming the part to fix. Sail stores a normalized form, so reading a policy back can return lowercased hosts and filled-in defaults; behavior is the same.
  • A policy’s rules cannot change after creation. Create and attach a new one. Renaming is allowed.

Attaching

A Sailbox holds at most one policy, and one policy can serve many Sailboxes.
A set or clear applies to HTTPS connections the Sailbox opens after the call succeeds. A connection that is already open keeps the previous policy until it closes, so close long-lived connections if the change must apply to the next request.

Where secrets live

Secrets are stored by Sail and added at the network edge as the request leaves the Sailbox. Nothing inside the Sailbox ever holds the value, and no Sail API returns it: sail secret show and sail secret list print names and timestamps only.
Output
To remove a secret, clear or replace the policy on every Sailbox that uses it, delete every policy that names it, then delete the secret. Sail refuses the other orders. sail http-policy list shows how many Sailboxes use each policy and which secrets it names.

Limitations

  • Policies apply to HTTPS only. Plain HTTP and raw TCP are unchanged.
  • A policy applies only when the client announces its HTTP version during the TLS handshake (ALPN), which almost every client does. For one that does not, add "missing_alpn": "http/1.1" next to rules on an exact host entry to treat its connections as HTTP/1.1.
  • Request bodies cannot be matched or changed, and responses cannot be changed.