# KMS overview

KMS is an Elixir toolkit for application-managed encryption.

It gives applications clean interfaces for common encryption scenarios:

- direct symmetric encryption primitives;
- field-level encryption in Phoenix/Ecto apps;
- embedded KMS key storage with SQLite by default;
- a standalone/remote KMS authority process;
- multi-user authorization with principals, sessions, factors, and bindings.

KMS is not one mandatory architecture. Choose the smallest mode that matches the security boundary you need.

## Start here

- New Phoenix app: [Quickstart](quickstart.md)
- Pattern selection: [Use cases](use_cases.md)
- App-wide encryption without KMS storage: [Application-wide encryption](use_cases/application_wide.md)
- SQLite/PostgreSQL persistence: [Database configuration](database.md)
- Root key providers: [Root master keys](rmk.md)
- AAD design: [Additional authenticated data](aad.md)
- Security posture: [Security](security.md)
- Install/config/API: [Installation](installation.md), [Configuration](configuration.md), [Elixir API](elixir-api.md), [HTTP API](http-api.md)

## Core concepts

### Crypto primitives

`KMS.Crypto` provides small AES-GCM helpers for encryption, decryption, random keys, and derived keys.

Use primitives directly when the application itself may decrypt at any time and you do not need KMS storage, sessions, or authorization.

See [Application-wide encryption](use_cases/application_wide.md).

### RMK: root master key

The RMK protects persisted KMS secret material.

Default provider:

- `KMS.RMK.Local`: file-backed local root key.

External providers:

- StackIT KMS
- AWS KMS
- Google Cloud KMS

Use local RMK for simple deployments where DB-only disclosure is the main risk. Use external RMK when database backups/storage need a separate key-service or IAM boundary.

See [Root master keys](rmk.md).

### KEK: key-encryption key

KMS stores and manages KEKs. Application code normally encrypts data through a KEK alias:

```elixir
{:ok, ciphertext} = KMS.encrypt_alias("secret", "owner:alice", aad: "document:123/body")
{:ok, plaintext} = KMS.decrypt_alias(ciphertext, "owner:alice", aad: "document:123/body")
```

A common pattern is one KEK alias per owner, tenant, document class, or application boundary.

### AAD: additional authenticated data

AAD is non-secret context authenticated with ciphertext. Decrypt requires the same AAD used for encrypt.

Good AAD examples:

```text
document:123/body
integration:456/api-token
webhook-endpoint:789/secret
```

AAD prevents ciphertext from being copied to another row/field and decrypted there.

See [Additional authenticated data](aad.md).

### Principals, sessions, factors, bindings

Use these when KMS, not the application alone, must enforce who can encrypt/decrypt.

- Principal: user or service identity.
- Session: bearer credential created after authentication.
- Factor: optional MFA step such as TOTP or WebAuthn.
- Binding: permission linking principal to scope/resource.

See [Sessions](sessions.md) and [Authentication factors](factors.md).

## Deployment modes

### 1. Crypto-only library

Use `KMS.Crypto` and optionally `KMS.RMK.Local` directly.

No KMS OTP application. No KMS database. No KMS HTTP API.

Good when:

- one app owns encryption and decryption;
- decrypt-at-any-time by the app is acceptable;
- database-only disclosure is the main risk;
- simple transparent encryption is enough.

Start with [Crypto-only library mode](use_cases/crypto_only.md) or [Application-wide encryption](use_cases/application_wide.md).

### 2. Embedded KMS in a Phoenix app

Start `:kms` with the Phoenix app and use the local client.

KMS stores its key tables in SQLite by default, while the app can keep PostgreSQL for normal app tables.

Good when:

- the app owns authorization;
- KMS should manage KEKs and RMK wrapping;
- field-level encryption should stay close to Ecto schemas/changesets.

Start with [Embedded KMS](use_cases/embedded.md) or the [Quickstart](quickstart.md).

### 3. Standalone KMS process

Run a dedicated KMS authority process with SQLite or PostgreSQL persistence.

Good when:

- multiple apps should share one KMS authority;
- app servers should not open the KMS database directly;
- operations want a separate backup/runtime boundary.

See [Standalone KMS with SQLite](use_cases/standalone.md).

### 4. Remote KMS service

Expose `KMS.API` over a private network/TLS and use `KMS.Client.Remote` from application servers.

Good when:

- apps should only call KMS over an API;
- RMK credentials and KMS database access must stay on KMS hosts;
- network/API controls are part of the security boundary.

See [Remote KMS service](use_cases/remote.md) and [Security stance](security/stance.md).

## Picking a pattern

| Requirement | Start with |
|---|---|
| Encrypt one or two app fields in Phoenix | [Quickstart](quickstart.md) |
| App can decrypt secrets whenever needed | [Crypto-only library mode](use_cases/crypto_only.md) or [Application-wide encryption](use_cases/application_wide.md) |
| One app should run KMS in-process | [Embedded KMS](use_cases/embedded.md) |
| Caller must supply high-entropy shared secret | [Shared passphrase documents](use_cases/passphrase.md) |
| KMS must enforce per-user decrypt permission | [Multi-user encryption](use_cases/multi_user_encryption.md) |
| Dedicated KMS with no PostgreSQL dependency | [Standalone KMS with SQLite](use_cases/standalone.md) |
| App servers call a central KMS authority | [Remote KMS service](use_cases/remote.md) |
| Stronger DB-backup separation | [External RMK providers](rmk.md#use-an-external-rmk-provider-for-stronger-separation) |

## Security boundaries

KMS helps most when boundaries are clear.

- Database-only compromise: protect with RMK-wrapped KMS secrets and/or app-wide encryption keys outside the database.
- KMS host compromise: local RMK and in-process keys are usually exposed; use external RMK and host hardening to reduce blast radius, not eliminate it.
- Running app compromise: if the app is allowed to decrypt, an attacker controlling that app can usually decrypt too.
- User-level authorization: use principals, sessions, factors, and bindings when KMS must decide who can decrypt.

Do not log plaintext, ciphertext payloads, session secrets, passwords, factor codes, RMK material, or private keys.

See [Security](security.md) and [Crash dumps](security/crash-dumps.md).

## Persistence

KMS defaults to SQLite. This keeps development and embedded deployments simple:

```sh
export KMS_DATA_DIR=/var/lib/kms
mix ecto.migrate
```

PostgreSQL remains supported:

```sh
export KMS_DATABASE_BACKEND=postgres
export KMS_DATABASE_URL=ecto://postgres:postgres@localhost/kms_prod
mix ecto.migrate
```

See [Database configuration](database.md).

## Operational docs

- [Observability](observability.md)
- [Database configuration](database.md)
- [Root master keys](rmk.md)
- [Security](security.md)
