Moat reference
Configuration, protocols, and access tokens for the ShrouDB server.
Moat runs every ShrouDB engine in one process. The engines share one encrypted storage layer and one set of access tokens. Any engine can instead run as a separate process, with Moat forwarding to it, so you can split out a busy engine later without changing client code.
Configuration
Moat reads a TOML file (default moat.toml, or --config, or MOAT_CONFIG). ${VAR} references are replaced with environment variables. Unknown keys are rejected at startup.
[server]
http_bind = "0.0.0.0:8200" # HTTP API
resp3_bind = "0.0.0.0:8201" # RESP3 wire protocol
# otel_endpoint = "http://localhost:4317"
# [server.tls]
# cert = "/etc/moat/tls/cert.pem"
# key = "/etc/moat/tls/key.pem"
[storage]
data_dir = "/data"
# wal_fsync_mode = "batched" # batched | per_write | periodic | none
[engines.cipher]
enabled = true
[engines.cipher.keyrings.customers]
algorithm = "aes-256-gcm"
rotation_days = 90
[engines.sigil]
enabled = true
access_ttl_secs = 900
refresh_ttl_secs = 604800
[engines.keep]
enabled = true
[engines.chronicle]
enabled = true
[engines.forge]
enabled = false
# Run an engine as a separate process instead:
# [engines.veil]
# mode = "remote"
# remote_addr = "veil.internal:6799" # host:port, no scheme
# remote_token = "${VEIL_TOKEN}"
[access.policies.admin]
token = "${MOAT_ADMIN_TOKEN}"
scopes = ["*:*/*"]
[access.policies.web]
token = "${WEB_APP_TOKEN}"
scopes = ["cipher:customers/*", "keep:*/READ"]Master key
Set SHROUDB_MASTER_KEY to 64 hex characters (32 bytes), or point SHROUDB_MASTER_KEY_FILEat a file containing it. Moat derives every engine's storage keys from it. Losing it means losing the data.
Access tokens
Each entry under [access.policies] is a token and a list of scopes. A scope has the form engine:namespace/access, where access is READ, WRITE, or *. Admin operations, such as creating a keyring, are checked as ADMIN on namespace _global, so they need a scope like cipher:*/*.
*:*/* # everything (admin)
cipher:*/* # all of Cipher
cipher:customers/* # only the customers keyring
keep:*/READ # read secrets, never write them
chronicle:*/READ # query the audit logIf no tokens are configured, Moat rejects every request (unless you set require_auth = false under [access], which is meant for local testing only). A request that a token isn't allowed to make gets a DENIED error (HTTP 403).
HTTP API
| Command | Args | Description |
|---|---|---|
| GET | /health | Health check, no token needed |
| POST | /v1/{engine} | Run a command: {"args": ["COMMAND", ...]} |
| * | /sigil/... | Sigil REST endpoints for login, refresh, JWKS, users |
Send Authorization: Bearer <token> and Content-Type: application/json.
RESP3 protocol
On port 8201, authenticate with AUTH <token>, then prefix each command with the engine name:
AUTH <token>
CIPHER ENCRYPT customers <base64>
KEEP GET db/prod/url
CHRONICLE QUERY ENGINE cipher LIMIT 20| Command | Args | Description |
|---|---|---|
| AUTH | <token> | Authenticate the connection |
| PING | Liveness check | |
| HEALTH | Health of every engine |
Shutdown
On SIGTERM or SIGINT, Moat stops accepting connections, finishes in-flight requests (up to 30 seconds), flushes the write-ahead log, and exits.
Related
- Engines: commands and config for each one.
- Security model: encryption, keys, and the production checklist.