Sealing and keys
The server holds some data that it can read: the values of server-readable spaces, TOTP secrets and similar items. It encrypts this data in the database. This page shows how that works and how to choose the key provider.
End-to-end encrypted folders are a different case. The server never has their keys. See Security.
The key hierarchy
flowchart TD
S["Unseal secret<br/>(passphrase or key file)"] -->|"Argon2id, or read raw"| K["KEK<br/>key encryption key"]
K -->|"unwraps"| D["Data key<br/>(random, in memory only)"]
D -->|"encrypts"| V["Server-readable values<br/>TOTP secrets, op values"]
W[("meta: seal.data_key<br/>wrapped data key")] --> K
- The server has one random data key. It encrypts all server-readable values.
- A key encryption key (KEK) wraps the data key. The wrapped data key is in the
metatable of the database. - A key provider supplies the KEK from the unseal secret.
- The data key is in memory only. The server does not keep the KEK after the start.
Sealed and unsealed
- Sealed: the server has no data key. The database file is only ciphertext for these values.
- Unsealed: the server unwrapped the data key at start. It can read and write server-readable values.
lasboltd unseals at start and does not listen before that. If the unseal fails, the program stops with an error. So a running server is always unsealed, and lasboltctl status shows state: unsealed. There is no command to seal a running server or to unseal it later. Stop the service to seal it.
Key providers
| Provider | Flag | Where the KEK comes from |
|---|---|---|
passphrase (default) | --key-provider passphrase | Argon2id of an operator passphrase. The passphrase comes from the terminal, or from the file in --unseal-passphrase-file. |
file | --key-provider file --key-file PATH | 32 raw bytes in a file. |
insecure-static | --dev only | A fixed key that is public in the source code. For tests. |
Passphrase from the terminal
Start lasboltd in a terminal. On the first start it asks for the passphrase twice. At each later start it asks once. The passphrase is never on the disk of the server. The service cannot restart by itself after a reboot, because nobody types the passphrase. Use this for a server that a person watches.
Passphrase from a file
head -c 32 /dev/urandom | base64 > /etc/lasbolt/passphrase
chmod 600 /etc/lasbolt/passphraseSet LASBOLT_UNSEAL_PASSPHRASE_FILE=/etc/lasbolt/passphrase. The server removes one trailing newline. A service restarts by itself. The cost: a person who can read the disk of the server has the passphrase and the database.
Key file
head -c 32 /dev/urandom > /etc/lasbolt/kek
chmod 400 /etc/lasbolt/kekSet LASBOLT_KEY_PROVIDER=file and LASBOLT_KEY_FILE=/etc/lasbolt/kek. The file must hold exactly 32 bytes. This has the same property as a passphrase file, and no Argon2id step. Use it when the file comes from a secret store at deploy time (see Deploy with Ansible).
Rules for secret files
- The file must not be readable by group or others. The server refuses a file with a wider mode, and names the file in the error.
- A wrong secret stops the start with
cannot unseal: wrong passphrase or key. - The provider is not stored in the database. You must start with the provider that made the data key. A passphrase on a database that a key file sealed gives the same error.
- The passphrase is not a user master password. The server never gets a user password.
What each choice protects against
| Threat | Terminal passphrase | Passphrase file or key file |
|---|---|---|
| Someone steals a disk, a snapshot or a backup | Protected. A guess of the passphrase costs Argon2id time for each try. | Protected, if the secret file is not on the same disk or snapshot. |
| Someone with root on the running host | Not protected. The data key is in memory. | Not protected. |
| Someone who can read the files of the host, with the server stopped | Protected | Not protected: the secret file is next to the data. |
| The host reboots at night | The service waits for a person. | The service starts by itself. |
| Lost secret | Data cannot be opened. There is no reset. | Data cannot be opened. There is no reset. |
Notes:
- A passphrase is only as strong as it is long. A person who gets the database or a backup can guess offline. Use a long random passphrase.
- Seal your backups to a separate key. Then a copy of a backup does not give a chance to guess the passphrase. See Backups and restore.
- A key file or passphrase file keeps the data safe from a lost disk only when the secret is on another medium, for example a secret store that the deploy tool reads. A deploy tool that puts the secret on the same disk gives protection from a stolen backup, not from a stolen host.
- The secret can only be changed by a deploy of the same value. There is no command to change the passphrase or the KEK of an existing database. Not available yet.
Keep the secret
Store the passphrase or the key file in two places away from the server, for example a password manager and a sealed envelope. Test that the stored copy opens a backup. See “Test the restore” in Backups and restore.