Skip to content

Server config & secrets

The server config is the YAML file for sluice serve --config. Secrets stay out of it: the file holds references. Configuration lists every key.

Example

Goal: keep the admin token and all secrets out of the file.

admin:
  enabled: true
  listen: ":9091"
  # The variable SLUICE_ADMIN__TOKEN sets the token.
identity:
  apiKeyPepper: "secret://file//etc/sluice/secrets/apikey-pepper"

audit:
  file:
    path: "./data/audit"
    genesis: "secret://env/SLUICE_AUDIT_GENESIS"

The start script sets them:

export SLUICE_ADMIN__TOKEN="demo-admin-token-from-env"
export SLUICE_AUDIT_GENESIS="server-config-demo-genesis"
# server.yaml names a file under /etc/sluice. This example keeps the file in data/.
export SLUICE_IDENTITY__APIKEYPEPPER="secret://file/$PWD/data/secrets/apikey-pepper"

A call without the token:

curl -s http://localhost:9091/admin/healthz
{
  "code": "ERR_UNAUTHORIZED",
  "message": "admin auth required"
}

What happened: SLUICE_ADMIN__TOKEN set admin.token, so the admin API refuses the call.

How Sluice loads the config

Later steps win:

  1. The built-in defaults.
  2. The file from --config.
  3. Environment variables. rest.listen becomes SLUICE_REST__LISTEN: prefix SLUICE_, upper case, __ for each dot.
  4. The flag --policies-dir, which replaces policies.directory.

A missing or empty policy directory is no error. Sluice starts and refuses every query.

Secret references

Reference Sluice reads
secret://env/NAME The environment variable NAME.
secret://file//etc/sluice/key The file /etc/sluice/key. The path must be absolute.

There are no other providers. Sluice refuses a secret file that group or others can write.

Where Keys that take a reference
Server config admin.token, identity.apiKeyPepper, audit.file.genesis, audit.s3.credentialsRef, approval.webhooks[].headersRef, mcp.tokenRef, mcp.apiKeyRef
SubjectBinding apiKeys[].hashRef, hmacSecretRef
DataSource credentialsRef, headersRef, tokenRef
RelationshipPolicy backend.tokenRef
Column mask arguments saltRef, keyRef, seed

admin.token holds the token itself, or a reference to it. An empty secret stops the start.

Sluice cuts spaces and line ends at the end of a secret of the server config. A secret file can end with a newline.

Sluice reads the secrets of the server config only at start. A reload reads the secrets of policy objects again. Until then, Sluice caches a mask or data source secret for 10 minutes.

Validate before you start

sluice config validate policies.d --config server.yaml --strict
server config OK: server.yaml
policies OK: policies.d (3 objects, digest <digest>)

An invalid file ends the command with status 3:

# Invalid on purpose: keyFile is missing and the pepper is not a secret reference.
rest:
  tls:
    certFile: "/etc/sluice/tls/server.crt"

identity:
  apiKeyPepper: "my-pepper-in-plain-text"
sluice config validate --config server-bad.yaml
rest.tls: certFile and keyFile are both required when a tls block is set
identity.apiKeyPepper: secrets: scheme "" is not "secret"
[exit status 3]

Limits

  • A wrong --config path is no error. Sluice then uses the defaults.
  • Without --strict, an unknown key in the server config is no error. Sluice ignores it, also at start.
  • config validate does not read secrets. A missing secret of the server config stops sluice serve.
  • budget.failClosed matters only at start. If the budget store does not open, true stops Sluice and false turns budgets off.

See also