KMS configuration is regular Elixir application config plus runtime environment variables.
Core settings
| Setting | Default | Purpose |
|---|---|---|
config :kms, :client | KMS.Client.Local | Client backend used by the KMS facade. |
config :kms, :components | :all | OTP children to start. Use a subset of :repo, :cache, :sessions, :fallbacks, and :api for narrow embedded use. |
config :kms, KMS.Repo, repo: | KMS.Repo.SQLite | Active KMS repo module. |
config :kms, :rmk_provider | KMS.RMK.Local | RMK provider for persisted KMS secret material. |
config :kms, :rmk_readiness_timeout_ms | 5000 | Maximum duration of startup and health RMK checks. |
config :kms, :session_hash_key | dev/test fallback only | HMAC key for session bearer verifiers. Required in prod. |
config :kms, :require_crash_dump_disabled | true in prod | Fail prod startup unless crash dumps are disabled. |
Database variables
| Env var | Default | Purpose |
|---|---|---|
KMS_DATABASE_BACKEND | sqlite | sqlite, sqlite3, postgres, or postgresql. |
KMS_DATA_DIR | dev: tmp/kms; prod: user data dir | Directory for default SQLite DB path. |
KMS_DATABASE_PATH | derived from KMS_DATA_DIR | Exact SQLite DB path. |
KMS_DATABASE_POOL_SIZE | 10; SQLite test 1 | Repo pool size. |
KMS_DATABASE_URL | unset | PostgreSQL URL. |
KMS_DATABASE_HOST | localhost | PostgreSQL host when URL unset. |
KMS_DATABASE_NAME | kms_<env> | PostgreSQL DB when URL unset. |
KMS_DATABASE_USER | postgres | PostgreSQL user. |
KMS_DATABASE_PASSWORD | postgres | PostgreSQL password. |
SQLite repo config
config :kms, KMS.Repo.SQLite,
database: "/var/lib/kms/kms.sqlite3",
journal_mode: :wal,
foreign_keys: :on,
busy_timeout: 5_000,
pool_size: 10,
priv: "priv/repo",
migration_primary_key: false,
migration_foreign_key: [type: :text],
migration_timestamps: [type: :utc_datetime_usec]PostgreSQL repo config
config :kms, KMS.Repo.Postgres,
url: System.fetch_env!("KMS_DATABASE_URL"),
pool_size: 10,
priv: "priv/repo",
migration_primary_key: false,
migration_foreign_key: [type: :text],
migration_timestamps: [type: :timestamptz]RMK provider config
Default local provider:
config :kms, :rmk_provider, KMS.RMK.Local
config :kms, KMS.RMK.Local, key_path: System.fetch_env!("KMS_RMK_LOCAL_KEY_PATH")External providers:
config :kms, :rmk_provider, KMS.RMK.StackIT
# config :kms, :rmk_provider, KMS.RMK.AWS
# config :kms, :rmk_provider, KMS.RMK.GCP
config :kms, :rmk_readiness_timeout_ms, 5_000KMS checks the configured provider during application startup and fails startup if it cannot access the RMK. The same bounded check runs for readiness probes.
See provider docs:
Remote client config
config :kms, :client, KMS.Client.Remote
config :kms, KMS.Client.Remote,
base_url: "https://kms.internal.example.com",
api_token: System.fetch_env!("KMS_REMOTE_API_TOKEN")Per-call overrides are also supported by the remote client:
KMS.encrypt_alias("secret", "alias", base_url: url, api_token: token)HTTP server config
config :kms, :api,
server: true,
port: 4004,
scheme: :http,
api_token: System.fetch_env!("KMS_API_TOKEN")All non-health routes require Authorization: Bearer <token>.
Sessions
config :kms, :session_default_ttl_ms, :timer.hours(1)
config :kms, :session_max_ttl_ms, :timer.hours(1)
config :kms, :session_idle_timeout_ms, :timer.hours(1)
config :kms, :session_max_lifetime_ms, :timer.hours(12)
config :kms, :session_cleanup_interval_ms, :timer.minutes(5)Login rate limit:
config :kms, :session_login_rate_limit,
principal: [limit: 5, window_ms: :timer.minutes(5)],
source: [limit: 50, window_ms: :timer.minutes(5)]Factor limits:
config :kms, :session_factor_attempt_limit, 5
config :kms, :session_factor_rate_limit, [limit: 5, window_ms: :timer.minutes(5)]See Sessions.
WebAuthn
config :kms, :webauthn,
rp_id: "example.com",
rp_name: "My App",
origins: ["https://example.com"],
attestation: "none",
user_verification: "preferred",
challenge_ttl_ms: :timer.minutes(5)See WebAuthn.
Cache
config :kms, :cache_ttl_ms, :timer.minutes(5)
config :kms, :rmk_cache_ttl_ms, :timer.minutes(5)
config :kms, :signing_key_cache_ttl_ms, :infinitySigning keys default to :infinity so hot signing does not repeatedly invoke an external RMK; override :signing_key_cache_ttl_ms to accept that latency and provider dependency in exchange for shorter cache residency. Infinite entries remain until explicit eviction or cache-process restart and increase process-memory exposure.
Per-call RMK cache override:
KMS.decrypt_alias(ciphertext, "alias", rmk_cache_ttl_ms: :timer.seconds(30))Fallback bootstrap
Fallback bootstrap and every fallback operation are local-only. The HTTP router does not compile fallback routes; use trusted in-process code or a controlled remote shell on the KMS host.
config :kms, :fallbacks_bootstrap, true
config :kms, :fallback_public_keys, [
%{name: "ops-2026", curve: "X25519", public_key: "..."}
]See Fallback recovery.