KDB knowledge

Encryption at rest

CREATE DATABASE x WITH (encryption = on) - every file, log record and backup of it is encrypted; without the master key a copied disk shows nothing.

An encrypted database keeps every file on disk encrypted: the tables, the log, the manifests and its backups. Someone who copies the disk, a VPS snapshot or a backup sees only random bytes. Only a KDB server that has the master key can read it.

It is off by default. You choose it for each database when you create it.

Plain databaseEncrypted database
Files on diskreadable with a hex editorrandom bytes
Backupsreadableencrypted too, and useless without the master key
Needsnothingthe master key when the server starts
Queries-the same SQL, the same results
Speed-see speed

Not covered: someone logged in to the running server as the kdb system user or as root can read the key and the memory. Users and roles and TLS protect the running server; encryption at rest protects the disk.

Turn it on

  1. Make a master key once, and keep it outside the data folder:
kdb key new > /etc/kdb/master.key        # 64 hex characters
chmod 600 /etc/kdb/master.key
  1. Give it to the server, in one of these ways:

Syntax:

KDB_MASTER_KEY=<64 hex characters, or base64 of 32 bytes>
KDB_MASTER_KEY_FILE=<a file holding the key as text, or 32 raw bytes>
  1. Create the database encrypted:
CREATE DATABASE payroll WITH (encryption = on);
USE payroll;
CREATE TABLE salaries (name STRING, amount DECIMAL(2));

In Docker, pass the key file as a secret and point KDB_MASTER_KEY_FILE at it, for example -v /etc/kdb/master.key:/run/secrets/kdb_master_key:ro -e KDB_MASTER_KEY_FILE=/run/secrets/kdb_master_key. Never put it in the data volume.

Keys

There are two keys, so that changing the master key never rewrites your data:

KeyWhat it isWhere it is
master key256 bits you give the serverKDB_MASTER_KEY or KDB_MASTER_KEY_FILE, never in the data folder
data key256 random bits, one per database<database>/_encryption.key, wrapped (encrypted) by the master key

Change the master key

Do this when a key may have leaked, or someone who knew it left:

  1. kdb key new for the new key.
  2. Start the server with the new key in KDB_MASTER_KEY and the old one in KDB_MASTER_KEY_PREVIOUS (or the ..._FILE forms).
  3. Each encrypted database re-wraps its data key with the new master key when it opens. It takes milliseconds, and no data file is rewritten. The server log says the data key is now wrapped by the new master key.
  4. Re-wrap the backups too: kdb key rotate <backups folder> (same variables).
  5. Remove KDB_MASTER_KEY_PREVIOUS.
KDB_MASTER_KEY_FILE=/etc/kdb/new.key KDB_MASTER_KEY_PREVIOUS_FILE=/etc/kdb/old.key \
  kdb key rotate /data/_backups/payroll

Backups you do not re-wrap still need the old key. Keep old keys as long as backups that need them exist.

Backups and restore

What is encrypted

PartHow
table files, catalog, manifests, backup manifests, temporary GROUP BY filesthe whole file, in 64 KB pieces, each with AES-256-GCM and its own check
the log (wal/, wal_archive/)every record body on its own. Record headers (length, number, checksum) and commit times stay plain, so recovery after a crash works exactly as before
kdb.lock, _encryption.keynot encrypted (the key file holds only the wrapped key)
memorynot encrypted (see above)

Speed

Measured on the development PC (Windows, x86-64 with AES instructions), a table of 1 million rows in 12 day partitions, a GROUP BY over all of it:

WorkPlainEncrypted
AES-256-GCM on one core-about 3-3.9 GB/s
scan of loaded data (in memory)292 ms302 ms (about +3%, within noise)
first scan after opening (reads and decrypts the files)749 ms883 ms (about +18%)
size of the data files60.2 MB61.6 MB (+2.3%)