RL-35: the downstream's relay keys, wrapped under a key file outside the store.
How it goes
The setting.INBUXA_RELAY_KEY_FILE names a file holding 32 random bytes in base64, as openssl rand -base64 32 writes them. Standard, URL-safe and unpadded base64 are all accepted.
What gets wrapped: the link CA key (and the next CA's key during a replacement), the sealing key, and each relay's recipient key. Each one is a Secret<T> (crates/features/src/relay/wrap.rs).
Without the setting, a secret is stored as a string, as before.
With it, a secret is stored as {"wrapped": nonce || ciphertext}, using AES-256-GCM with a random nonce and fixed AAD.
When a key is opened: only where it's used, with .open(). Reading a record never needs the key file, so the console still lists relays while the file is missing.
Turning it on. The link service's reconcile calls wrap_stored, which rewrites any key still stored in the clear with a compare-and-swap. A secret read in the clear is also wrapped whenever it is next written.
Without the file, or with one that can't be read or holds another key, link_keys fails before any link starts. Each link's lastError gives the reason in plain words, for example The relay keys are wrapped: set INBUXA_RELAY_KEY_FILE to the key file they were wrapped with.
No key in the clear while the setting is broken. If the setting names a file that can't be read, a secret in the clear refuses to serialize, so it is never written unwrapped.
Taking the setting away doesn't unwrap the keys. That case is the "no link, says why" case above.
keysWrapped is a new server-set property on inbuxa:Relay.
For the test:wrap::set_key_file swaps the key file at runtime, and stored_bytes returns the raw stored records.
Tests
Unit tests: wrap/open, a new nonce on every wrap, the wrong key, a tampered byte, the stored forms, and key file parsing. Features relay tests: 18. Services relay tests: 3.
relay_link_tests (RL-T27), against the real relay binary:
before the file is set, the stored bytes hold the keys in the clear;
once it is set, no key appears in them, keysWrapped is true, and the relay stays linked;
with the file taken away and the relay turned off and on again, there is no link and lastError names INBUXA_RELAY_KEY_FILE, while mail sent meanwhile is held;
with the file back, the relay links again and the held message is delivered, which proves the sealing key still opens.
relay_tests:keysWrapped is false without a key file.
Checks: fmt, clippy on the changed files, the fork checks and their tests, and expr-schema.
The console part, a note on the Relays page when the keys are wrapped, follows in inbuxa-admin.
RL-35: the downstream's relay keys, wrapped under a key file outside the store.
## How it goes
- **The setting.** `INBUXA_RELAY_KEY_FILE` names a file holding 32 random bytes in base64, as `openssl rand -base64 32` writes them. Standard, URL-safe and unpadded base64 are all accepted.
- **What gets wrapped:** the link CA key (and the next CA's key during a replacement), the sealing key, and each relay's recipient key. Each one is a `Secret<T>` (`crates/features/src/relay/wrap.rs`).
- **Without the setting**, a secret is stored as a string, as before.
- **With it**, a secret is stored as `{"wrapped": nonce || ciphertext}`, using AES-256-GCM with a random nonce and fixed AAD.
- **When a key is opened:** only where it's used, with `.open()`. Reading a record never needs the key file, so the console still lists relays while the file is missing.
- **Turning it on.** The link service's reconcile calls `wrap_stored`, which rewrites any key still stored in the clear with a compare-and-swap. A secret read in the clear is also wrapped whenever it is next written.
- **Without the file**, or with one that can't be read or holds another key, `link_keys` fails before any link starts. Each link's `lastError` gives the reason in plain words, for example *The relay keys are wrapped: set INBUXA_RELAY_KEY_FILE to the key file they were wrapped with.*
- **No key in the clear while the setting is broken.** If the setting names a file that can't be read, a secret in the clear refuses to serialize, so it is never written unwrapped.
- **Taking the setting away** doesn't unwrap the keys. That case is the "no link, says why" case above.
- **`keysWrapped`** is a new server-set property on `inbuxa:Relay`.
- **For the test:** `wrap::set_key_file` swaps the key file at runtime, and `stored_bytes` returns the raw stored records.
## Tests
- **Unit tests:** wrap/open, a new nonce on every wrap, the wrong key, a tampered byte, the stored forms, and key file parsing. Features relay tests: 18. Services relay tests: 3.
- **`relay_link_tests` (RL-T27)**, against the real relay binary:
- before the file is set, the stored bytes hold the keys in the clear;
- once it is set, no key appears in them, `keysWrapped` is true, and the relay stays linked;
- with the file taken away and the relay turned off and on again, there is no link and `lastError` names `INBUXA_RELAY_KEY_FILE`, while mail sent meanwhile is held;
- with the file back, the relay links again and the held message is delivered, which proves the sealing key still opens.
- **`relay_tests`:** `keysWrapped` is false without a key file.
- **Checks:** fmt, clippy on the changed files, the fork checks and their tests, and expr-schema.
The console part, a note on the Relays page when the keys are wrapped, follows in inbuxa-admin.
With INBUXA_RELAY_KEY_FILE naming a file of 32 random bytes in base64,
the link CA key (and the next one's, during a replacement), the sealing
key and each relay's recipient key are stored wrapped with AES-256-GCM,
as {"wrapped": ...} where each was a string. A copy of the store or a
backup alone then can't issue node certificates or open held mail.
The link service wraps any key still in the clear at its next scan.
Without the file, with one that can't be read, or with another key, a
node starts no relay link, and each link's lastError says why; while the
setting names a file that can't be read, no key is written in the clear.
Without the setting, keys are stored as before. inbuxa:Relay shows
keysWrapped.
Tested: unit tests of the wrapping, the stored forms and the key file;
the server's relay link test against the real relay binary (RL-T27: no
key in the clear in the stored bytes once wrapped, still linked; with
the file taken away, no link and the reason; with it back, linked again
and the mail held meanwhile delivered), and relay_tests.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
RL-35: the downstream's relay keys, wrapped under a key file outside the store.
How it goes
INBUXA_RELAY_KEY_FILEnames a file holding 32 random bytes in base64, asopenssl rand -base64 32writes them. Standard, URL-safe and unpadded base64 are all accepted.Secret<T>(crates/features/src/relay/wrap.rs).{"wrapped": nonce || ciphertext}, using AES-256-GCM with a random nonce and fixed AAD..open(). Reading a record never needs the key file, so the console still lists relays while the file is missing.wrap_stored, which rewrites any key still stored in the clear with a compare-and-swap. A secret read in the clear is also wrapped whenever it is next written.link_keysfails before any link starts. Each link'slastErrorgives the reason in plain words, for example The relay keys are wrapped: set INBUXA_RELAY_KEY_FILE to the key file they were wrapped with.keysWrappedis a new server-set property oninbuxa:Relay.wrap::set_key_fileswaps the key file at runtime, andstored_bytesreturns the raw stored records.Tests
relay_link_tests(RL-T27), against the real relay binary:keysWrappedis true, and the relay stays linked;lastErrornamesINBUXA_RELAY_KEY_FILE, while mail sent meanwhile is held;relay_tests:keysWrappedis false without a key file.The console part, a note on the Relays page when the keys are wrapped, follows in inbuxa-admin.
With INBUXA_RELAY_KEY_FILE naming a file of 32 random bytes in base64, the link CA key (and the next one's, during a replacement), the sealing key and each relay's recipient key are stored wrapped with AES-256-GCM, as {"wrapped": ...} where each was a string. A copy of the store or a backup alone then can't issue node certificates or open held mail. The link service wraps any key still in the clear at its next scan. Without the file, with one that can't be read, or with another key, a node starts no relay link, and each link's lastError says why; while the setting names a file that can't be read, no key is written in the clear. Without the setting, keys are stored as before. inbuxa:Relay shows keysWrapped. Tested: unit tests of the wrapping, the stored forms and the key file; the server's relay link test against the real relay binary (RL-T27: no key in the clear in the stored bytes once wrapped, still linked; with the file taken away, no link and the reason; with it back, linked again and the mail held meanwhile delivered), and relay_tests.