Documentation menu

Platform

Named variables

Map a stable name such as LOG_SERVER_TX1_S to one field of an existing credential, then resolve %%LOG_SERVER_TX1_S%% when a playbook, application or build needs it. Assignments hold references, never copied values, so rotation changes the next resolved value without editing templates.

Create an assignment

Use Secret Variables in the dashboard, the desktop app's Variables tab, an SDK, Terraform or the CLI:

# A root_credential stores its password under the password field
ss variables assign LOG_SERVER_TX1_S root_credential CREDENTIAL_UUID password
# A password record uses the value field
ss variables assign LOG_SERVER_TX1_S password PASSWORD_UUID value

ss variables list
ss variables delete LOG_SERVER_TX1_S
  • Managing assignments needs variables:read and variables:write. The built-in member, user and developer roles have both, as do admins.
  • The credential must exist and belong to the same account.
  • The field is a literal top-level key of the stored credential's data, not a JSONPath expression. Field names match [A-Za-z_][A-Za-z0-9_.-]{0,127}.
  • Assignment IDs stay the same across updates; deleting and recreating an assignment gives it a new ID.

Supported target types: secret, password, api_token, certificate, ssh_key, gpg_key, openssl_key, ntlm_hash, computer_credential, wifi_credential, windows_credential, social_credential, disk_credential, service_config_credential, root_credential, ldap_bind_credential, integration_credential and code_signing_key.

Resolution rules

RuleDetail
Names[A-Z_][A-Z0-9_]{0,127}, case-sensitive, unique per account
Token%%NAME%% resolves the current string field. Empty strings are valid.
Escape%%%% is a literal %%, so %%%%NAME%%%% becomes %%NAME%%
Single passInserted values are never scanned for more tokens
All or nothingA missing variable (404), denied permission (403), expired secret or inactive API token (410), missing or non-string field (422) or size limit (413) fails the whole request. No partial output is returned.
ConsistencyRepeated references to one name use one value per request. Different variables are not read as an atomic snapshot.
Limits1 MiB request, 4 MiB response, 256 distinct names, 64 levels of document nesting
PrivacyResponses carry Cache-Control: no-store. Audit events record the assignment and credential reference, never templates or values.

Resolving also needs read access to each underlying credential, and key types additionally need export:read. Knowing a variable name grants no access.

REST API

MethodEndpointResult
PUT/api/v1/variables/NAMEAssign or update {secret_type, secret_id, field}
GET/api/v1/variables/NAMEAssignment metadata
GET/api/v1/variables{variables: [...]}, up to 1,000 assignments
DELETE/api/v1/variables/NAMEDelete the assignment; 204
POST/api/v1/variables/resolveResolve text or a JSON document

Text

POST /api/v1/variables/resolve
{"template": "sudo_password=%%LOG_SERVER_TX1_S%%"}

{"rendered": "sudo_password=...", "variables": ["LOG_SERVER_TX1_S"]}

JSON document

POST /api/v1/variables/resolve
{"document": {"password": "%%LOG_SERVER_TX1_S%%", "port": 443}}

The document response has document and variables. Only string values are processed; keys, numbers, booleans, null and structure are preserved, and quotes or newlines in values are encoded as JSON data.

Raw text rendering does not escape shell, YAML, SQL or HCL syntax. Prefer document resolution, or the consumer's own variable input, when generating configuration.

Clients and tools

ConsumerAssignResolve textResolve JSON
Pythonassign_variablerender(text)resolve_document(doc)
Node.js / TypeScriptassignVariablerender(text)resolveDocument(doc)
PHPassignVariablerender(text)resolveDocument(doc)
ss CLIss variables assignss render FILEss render --json FILE
Device agentAdmin grants in a profilesecretserver-agent render --input FILEadd --json
Desktop appVariables tabResolve template buttonUse an SDK

Ansible

vars:
  ansible_become_password: "{{ lookup('secretserver', '%%LOG_SERVER_TX1_S%%') }}"

Supply SS_API_KEY and SS_API_URL or the lookup's api_key and api_url options, and set no_log: true on tasks that use the result. render=true treats a term as a template even without tokens. Placing %%NAME%% in ordinary YAML does nothing; the lookup must be invoked.

Terraform

resource "secretserver_variable" "sudo" {
  name        = "LOG_SERVER_TX1_S"
  secret_type = "root_credential"
  secret_id   = var.root_credential_id
  field       = "password"
}

ephemeral "secretserver_template" "sudo" {
  template   = "%%LOG_SERVER_TX1_S%%"
  depends_on = [secretserver_variable.sudo]
}

The resource stores only assignment metadata in state. Use the ephemeral value only where Terraform allows ephemeral values (Terraform 1.10 or newer). There is deliberately no ordinary template data source.

Device agent grants

{"alias": "sudo-password", "service": "variable.resolve", "resource": "VARIABLE_UUID"}

A device resolves only the variable IDs granted to its profile, through signed POST /api/v1/agent/variables/resolve requests. secretserver-agent run writes each such grant to a private <alias>.json file in its output directory.

MCP bridge

Resolution is off by default. SECRETSERVER_ENABLE_SECRET_RESOLUTION=1 together with an allowlist in SECRETSERVER_RESOLVE_ALLOW=NAME[,NAME...] registers resolve_secret_template, whose plaintext result enters model context. The bridge refuses to start with the switch on and no allowlist.

Rendered files

umask 077
ss render --json application.template.json > application.private.json
# or with an enrolled device identity
secretserver-agent render --json --input application.template.json > application.private.json

Rendered output contains plaintext secrets. Keep it out of source control, build logs, caches and published artifacts, and prefer runtime injection for services. A failed command emits nothing, but shell redirection may already have truncated the destination; render to a temporary file and rename it on success when replacing live configuration.