Packages
Key management service with embedded OTP runtime, optional HTTP API, SQLite/PostgreSQL storage, and external RMK providers
Current section
Files
Jump to
Current section
Files
docs/configuration.md
# Configuration
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. |
See [Database configuration](database.md).
## SQLite repo config
```elixir
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
```elixir
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:
```elixir
config :kms, :rmk_provider, KMS.RMK.Local
config :kms, KMS.RMK.Local, key_path: System.fetch_env!("KMS_RMK_LOCAL_KEY_PATH")
```
External providers:
```elixir
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_000
```
KMS 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:
- [Local RMK](rmk/local.md)
- [StackIT RMK](rmk/stackit.md)
- [AWS RMK](rmk/aws.md)
- [GCP RMK](rmk/gcp.md)
## Remote client config
```elixir
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:
```elixir
KMS.encrypt_alias("secret", "alias", base_url: url, api_token: token)
```
## HTTP server config
```elixir
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
```elixir
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:
```elixir
config :kms, :session_login_rate_limit,
principal: [limit: 5, window_ms: :timer.minutes(5)],
source: [limit: 50, window_ms: :timer.minutes(5)]
```
Factor limits:
```elixir
config :kms, :session_factor_attempt_limit, 5
config :kms, :session_factor_rate_limit, [limit: 5, window_ms: :timer.minutes(5)]
```
See [Sessions](sessions.md).
## WebAuthn
```elixir
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](factors/webauthn.md).
## Cache
```elixir
config :kms, :cache_ttl_ms, :timer.minutes(5)
config :kms, :rmk_cache_ttl_ms, :timer.minutes(5)
config :kms, :signing_key_cache_ttl_ms, :infinity
```
Signing 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:
```elixir
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.
```elixir
config :kms, :fallbacks_bootstrap, true
config :kms, :fallback_public_keys, [
%{name: "ops-2026", curve: "X25519", public_key: "..."}
]
```
See [Fallback recovery](fallback-recovery.md).