> ## Documentation Index
> Fetch the complete documentation index at: https://engineering.unkey.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Encryption key service backed by object storage

Vault is Unkey's centralized encryption service. It owns data encryption keys (DEKs) and lets runtime services encrypt or decrypt sensitive payloads without embedding key material in application code or databases.

The service stores encrypted DEKs in S3-compatible object storage and protects them with a master key encryption key (KEK). Vault is stateless aside from an in-memory cache, so durable key material lives outside the service and is loaded on demand.

## Place in the stack

Vault sits alongside the core control-plane services and is treated as shared infrastructure for encryption. Services call Vault when they need to encrypt secrets or decrypt stored values. This keeps key material out of MySQL, ClickHouse, and service binaries.

Known runtime callers include the API service, frontline, krane, control worker workflows, and internal analytics. Vault is not exposed to end users and is accessed only by internal services over Connect RPC.

## Responsibilities

Vault is responsible for:

* issuing and storing DEKs per keyring
* encrypting and decrypting payloads with DEKs
* validating encrypted payload structure before decryption
* re-encrypting payloads on demand with the latest DEK
* re-encrypting stored DEKs during master key rotation

## RPC surface

The service uses Connect RPC and exposes these methods:

* `Liveness` returns `ok` and does not require authentication
* `Encrypt` creates or reuses the latest DEK for a keyring and returns a base64-encoded `Encrypted` payload
* `Decrypt` validates and decrypts a base64-encoded `Encrypted` payload
* `ReEncrypt` decrypts a payload, clears the DEK cache, and re-encrypts with the latest DEK for the keyring

`ReEncrypt` ignores the optional `key_id` field in the request and always uses the latest DEK.

`Decrypt` validates the encrypted payload before attempting decryption. It enforces a 12-byte GCM nonce, a ciphertext length of at least 16 bytes, and a non-empty encryption key ID.

## Key model

Vault works with two key types defined in [`svc/vault/proto/vault/v1/object.proto`](https://github.com/unkeyed/unkey/blob/main/svc/vault/proto/vault/v1/object.proto):

* `KeyEncryptionKey` (KEK), the master key used to encrypt DEKs
* `DataEncryptionKey` (DEK), the per-keyring data key used for payload encryption

Encrypted payloads use AES-256-GCM and are serialized into the `Encrypted` message, which includes the nonce, ciphertext, and the KEK or DEK identifier used for encryption.

## Object layout

Vault stores encrypted DEKs in an S3-compatible object store. Objects use a keyring prefix and the DEK ID.

Object keys:

```
keyring/<ring_id>/<dek_id>
keyring/<ring_id>/LATEST
```

`LATEST` stores the most recent DEK for a keyring and is updated on key creation.

## Object format

Stored object values are serialized `EncryptedDataEncryptionKey` protobuf messages from [`svc/vault/proto/vault/v1/object.proto`](https://github.com/unkeyed/unkey/blob/main/svc/vault/proto/vault/v1/object.proto).

Decoded fields:

* `id` and `created_at` from the DEK
* `encrypted.algorithm` set to `AES_256_GCM`
* `encrypted.nonce` and `encrypted.ciphertext` from the KEK encryption
* `encrypted.encryption_key_id` set to the KEK identifier
* `encrypted.time` set to the encryption timestamp in Unix milliseconds

## Consistency and caching

Vault reads from storage on cache miss and caches DEKs in memory. The cache keeps fresh entries for one hour, allows stale entries for 24 hours, and stores up to 10,000 DEKs per instance.

If storage is eventually consistent, cache misses can return stale keys. The `LATEST` pointer is the source of truth for the newest DEK, so stale reads can temporarily select older keys.

`ReEncrypt` clears the cache to ensure the latest DEK is fetched after key rotation.

## Key rotation and re-encryption

Vault accepts a current master key and an optional previous master key. Both are used for decryption, while new DEKs are always encrypted with the current master key.

Vault can re-encrypt all stored DEKs by walking object storage and rewriting each `EncryptedDataEncryptionKey` with the current master key. This is implemented by `RollDeks` and `Keyring.RollKeys`, and it is not exposed as an RPC method.

## High availability

Vault is stateless aside from the in-memory cache and uses S3 as the system of record. This allows horizontal scaling with multiple replicas.

HA considerations:

* All replicas must share the same S3 bucket and master key.
* Cache state is per-pod and can diverge. Cache TTLs bound staleness.
* If a replica restarts, it repopulates cache on demand from S3.
