Configuration
Docs path: Operate / Configuration
config.toml normally lives at /etc/openkms/config.toml. The canonical
example in the repository is
examples/config.toml.
The drift test in
tests/docs_drift.rs
parses and .validate()-checks that file, so documented field names stay live.
The loader rejects duplicate key labels, duplicate object_id values, missing
policy blocks, and invalid allowlist strings before the service starts.
Evaluation order for the policy fields is in
Policy Authoring.
[server]
Section titled “[server]”| Field | Required | Default | Description |
|---|---|---|---|
listen | yes | — | Bind address. 127.0.0.1:9443 for loopback / reverse proxy; 0.0.0.0:PORT only on a hardened staging host. |
signer_token_file | yes | — | Bearer token for /sign/* and /policy/*. Must be 0600. |
admin_token_file | yes | — | Bearer token for /admin/*. Must be 0600. |
inflight_limit | no | 64 | Max concurrent in-flight signing requests. Excess returns 503 from the buffer/limit layer. |
replay_window_secs | no | 120 | Replay-cache lifetime for deterministic signatures. |
| Field | Required | Default | Description |
|---|---|---|---|
connector_url | yes | — | yubihsm-connector HTTP endpoint, normally on loopback. |
auth_key_id | yes | — | YubiHSM auth-key slot the runtime authenticates as. 3 is the signer slot from openkms setup. |
password_file | yes | — | 64 hex digits (32 bytes) for the signer auth-key password. Generate with openkms ceremony print-signer-password. Must be 0600. |
[audit]
Section titled “[audit]”| Field | Required | Default | Description |
|---|---|---|---|
path | yes | — | Append-only JSONL audit log (typically under state_dir). |
hmac_key_file | no | — | When set, every audit record includes an HMAC of the prior chain. The key file must be 0600. |
state_dir
Section titled “state_dir”Top-level path used for runtime persistence: admin policy overlays,
kill-switch flags, and the audit log when [audit].path is relative. Set this
on a writable, dedicated directory (e.g. /var/lib/openkms).
[cosmos]
Section titled “[cosmos]”| Field | Required | Default | Description |
|---|---|---|---|
accepted_pubkey_type_urls | no | secp256k1, Ethermint ethsecp256k1, Injective ethsecp256k1 | AuthInfo.signer_infos[].public_key.type_url values the decoder will accept. Add chain-specific URLs without code changes. |
[[keys]]
Section titled “[[keys]]”One block per signing key.
| Field | Required | Default | Description |
|---|---|---|---|
label | yes | — | Stable identifier used in HTTP requests and the audit log. |
chain | yes | — | solana or cosmos. |
object_id | yes | — | YubiHSM asymmetric-key object id (decimal or 0x0100). |
derivation_path | no | — | BIP-32 / SLIP-10 path used when keys provision imports a deterministic key (Cosmos: m/44'/118'/0'/0/0; Solana: m/44'/501'/0'/0'). |
address_style | no | cosmos | cosmos, evm, or solana. Drives address derivation and recipient comparisons. |
default_hrp | no | — | Bech32 prefix for Cosmos-style derivations (e.g. cosmos, osmo). |
policy | yes | — | [keys.policy] block (see below). |
Solana [[keys]] example
Section titled “Solana [[keys]] example”[[keys]]label = "solana-hot-0"chain = "solana"object_id = 0x0101
[keys.policy]enabled = truemax_signs_per_minute = 30max_signs_per_day = 5000per_tx_cap_lamports = "5000000000"
[[keys.policy.allowed_programs]] id = "11111111111111111111111111111111" comment = "system transfers"Cosmos [[keys]] example
Section titled “Cosmos [[keys]] example”[[keys]]label = "cosmos-hub-0"chain = "cosmos"object_id = 0x0100derivation_path = "m/44'/118'/0'/0/0"address_style = "cosmos"default_hrp = "cosmos"
[keys.policy]enabled = truemax_signs_per_minute = 6max_signs_per_hour = 120max_signs_per_day = 500daily_cap_lamports = "5000000000"per_tx_cap_lamports = "500000000"
[[keys.policy.allowed_messages]] type_url = "/cosmos.bank.v1beta1.MsgSend" allowed_recipients = ["cosmos1replace_me"] per_tx_cap = { uatom = "500000000" }[keys.policy]
Section titled “[keys.policy]”| Field | Default | Description |
|---|---|---|
enabled | false | Master switch for the key. The admin kill switch and overlays can override this at runtime. |
max_signs_per_minute | unset | Token-bucket rate limit. |
max_signs_per_hour | unset | Token-bucket rate limit. |
max_signs_per_day | unset | Token-bucket rate limit. |
per_tx_cap_lamports | unset | Solana keys: cap on outgoing lamport totals per signed transaction. Cosmos keys: prefer denom-keyed per_tx_cap inside [[allowed_messages]]. |
daily_cap_lamports | unset | Solana keys: cap on accepted signed transfers in a rolling 24h window. |
[[keys.policy.allowed_programs]] | empty | Solana program allowlist (id, optional comment). Empty means no programs are permitted. |
[[keys.policy.allowed_messages]] | empty | Cosmos message-type allowlist with optional allowed_recipients, allowed_contracts, allowed_methods, and denom-keyed per_tx_cap. Empty means no Cosmos message types are permitted. |
[[keys.policy.allowed_recipients]] | empty | Recipient allowlist tied to a program family. |
Empty allowlists are meaningful: a Solana key with no allowed_programs and a
Cosmos key with no allowed_messages will deny every signing request.
Secret files
Section titled “Secret files”These must be mode 0600 or openKMS refuses to start:
signer.tokenadmin.tokenhsm-passwordaudit-hmac.key(whenhmac_key_fileis set)