Encryption at rest
One key file encrypts every file the store writes and seals every backup; a store opens only the way it was created, and moving to a new key is a backup and a restore.
From 0.21.0-beta a store can be encrypted under a key you hold. It is opt-in:
a store created without a key is not encrypted, and stays that way.
openssl rand 32 > store.key && chmod 600 store.key
tessaridb ./data --encryption-key-file store.key --serve 0.0.0.0:9080
TESSARIDB_ENCRYPTION_KEY_FILE stands for the flag, which is how a
container is given it. The file holds exactly 32
bytes and, on Unix, must not be readable by its group or by others; any other
file is refused, saying which check failed:
the encryption key file store.key: may be read by others (mode 644); `chmod 600` it
What is encrypted
Given a key, a node encrypts every file its storage engine writes — the
tables, the write-ahead log, the manifest, the engine's own options and log — and
seals every backup it produces: a snapshot, a log or a script, whether it is
answered by BACKUP, written by BACKUP … TO, streamed by GET /backup, or
written by --backup, --snapshot and --dump.
The key is never used as it is. Three subkeys are drawn from it: one for the
engine's files, one for backups, and one for a marker file, ENCRYPTION, that
records which key the store was created under. The engine's files are XChaCha20
with a random nonce per file, and their integrity is the engine's own checksums.
A sealed backup is ChaCha20-Poly1305 in 64 KiB chunks, each bound to its position
and to whether it is the last, so a backup cut short, reordered, extended or
altered does not open.
A store opens only the way it was created
The node says which way is wrong before the engine reads anything:
| opened | answer |
|---|---|
| an encrypted store, with no key | the store at ./data is encrypted; it opens only with its key |
| an encrypted store, under another key | the encryption key does not open the store at ./data: it was encrypted under another key |
| a plain store, given a key | the store at ./data is not encrypted, and an encryption key was given |
A sealed backup opens only where its key is
RESTORE SCRIPT FROM, --restore and --verify open a sealed backup with the
node's key. Without one it is refused — this backup is sealed; it opens only on
a node given its encryption key — and under another key it does not open either.
A plain backup still restores into an encrypted store.
tessaridb --encryption-key-file store.key --verify state.tessarisnap
Moving to a new key
Nothing rewrites a store in place. A store moves to a new key by a backup, and a
restore of that backup into a new store under the new key — --backup-key-file
names the key the backup was sealed under when it is not the new store's:
tessaridb ./data --encryption-key-file old.key --backup state.tessarisnap
tessaridb ./renewed --encryption-key-file new.key \
--backup-key-file old.key --restore state.tessarisnap
A lost key is a lost store and a lost set of backups. Keep it somewhere the store is not — in a container, a secret mount rather than the store's volume.
What it protects, and what it does not
The disk and the backups: a stolen volume, a discarded drive, a backup file left in a bucket. Not a running node — it holds the key in memory and answers anyone with a credential, and privileged code on the host can read both — and not the traffic, which is Encryption in transit.
| where | holds | encrypted |
|---|---|---|
| the store's directory | every record, the catalog, the log | yes, under the engine subkey |
ENCRYPTION | a sealed constant that says which key | holds no data |
| a backup file, wherever it is copied | every record of its part | sealed, under the backup subkey |
<name>.partial while BACKUP … TO writes | the same | sealed |
the node's temporary folder while GET /backup spools | the same | sealed |
| the key file | the key | no — keep it apart from the store |
| the node's memory | everything it has read | no |
| the node's own log lines on standard error | events and failure reasons, which can name a table or an id | no |
A vault keeps its sealed values sealed under its own key whether or not the store is encrypted; the two are separate keys with separate custody.