Summary
Store RBAC permission data in a standalone encrypted file (separate from the DuckDB telemetry store) with a pluggable key-provider abstraction. Only two provider backends are supported:
- systemd-creds (default, no library linkage — invoked as a subprocess)
- tpm2-tss with the mbedtls crypto backend (for environments that need direct TPM 2.0 binding without systemd)
No OpenSSL. No other backends (no libsecret, no passphrase prompt, no PKCS#11, no cloud KMS) are in scope for this issue.
Motivation
- RBAC data is small, slow-changing, and not joined with telemetry — no benefit from placing it inside DuckDB.
- DuckDB's native at-rest encryption requires the key to appear as a literal inside an
ATTACH SQL statement, which complicates key hygiene and has no dedicated C API.
- An independent encrypted RBAC file allows key material to be unwrapped only at load time, kept in locked memory, and zeroed immediately after use.
- wyrelog's GPL-3.0-or-later + Commercial dual license requires permissive or compatible dependencies; OpenSSL is excluded by project policy.
Scope
File format
- Container: libsodium
crypto_secretstream_xchacha20poly1305 (AEAD, chunked)
- Atomic writes: temp file +
fsync + rename
- File mode:
0600, dedicated UID/GID
- Header carries format version and provider identifier (
systemd-creds | tpm2) so a file can be opened by the correct unwrap path without configuration lookup
KeyProvider interface (C)
typedef struct _WyrelogKeyProvider WyrelogKeyProvider;
gboolean wyrelog_key_provider_unwrap (WyrelogKeyProvider *provider,
guint8 *dek_out, /* 32 bytes */
GError **error);
gboolean wyrelog_key_provider_wrap (WyrelogKeyProvider *provider,
const guint8 *dek_in, /* 32 bytes */
GError **error);
- DEK buffers allocated via
sodium_malloc + sodium_mlock
sodium_memzero on free, no logging of key material or SQL/command lines containing keys
Backend: systemd-creds
- No library linkage; wyrelog spawns
systemd-creds encrypt/decrypt with the DEK on stdin/stdout
- On TPM-equipped hosts systemd transparently seals to TPM2; otherwise falls back to the host key
- Minimum systemd version documented (249+)
Backend: tpm2-tss + mbedtls
- Build option
--with-crypto=mbed on tpm2-tss
- Seal DEK under the owner hierarchy SRK; optional PCR policy (documented but off by default to avoid operational surprises across kernel/firmware updates)
- Unseal path uses the ESYS API; sealed blob stored next to the RBAC file
Meson wiring
- New dependencies:
libsodium (unconditional), tpm2-tss ESYS (optional, feature-flagged -Dtpm2=enabled)
- Build matrix adds one job per provider
THIRD_PARTY_NOTICES.md seeded with libsodium (ISC), mbedtls (Apache-2.0), and tpm2-tss (BSD-2-Clause) entries
Out of scope
- Passphrase / libsecret / PKCS#11 / cloud KMS providers
- OpenSSL-based TPM stacks (
tpm2-openssl, tpm2-tss-engine)
- Key rotation UX beyond a single
wyrelog rbac rotate-key command that re-encrypts in place
- Placing RBAC inside DuckDB
Acceptance criteria
References
Summary
Store RBAC permission data in a standalone encrypted file (separate from the DuckDB telemetry store) with a pluggable key-provider abstraction. Only two provider backends are supported:
No OpenSSL. No other backends (no libsecret, no passphrase prompt, no PKCS#11, no cloud KMS) are in scope for this issue.
Motivation
ATTACHSQL statement, which complicates key hygiene and has no dedicated C API.Scope
File format
crypto_secretstream_xchacha20poly1305(AEAD, chunked)fsync+rename0600, dedicated UID/GIDsystemd-creds|tpm2) so a file can be opened by the correct unwrap path without configuration lookupKeyProvider interface (C)
sodium_malloc+sodium_mlocksodium_memzeroon free, no logging of key material or SQL/command lines containing keysBackend: systemd-creds
systemd-creds encrypt/decryptwith the DEK on stdin/stdoutBackend: tpm2-tss + mbedtls
--with-crypto=mbedon tpm2-tssMeson wiring
libsodium(unconditional),tpm2-tssESYS (optional, feature-flagged-Dtpm2=enabled)THIRD_PARTY_NOTICES.mdseeded with libsodium (ISC), mbedtls (Apache-2.0), and tpm2-tss (BSD-2-Clause) entriesOut of scope
tpm2-openssl,tpm2-tss-engine)wyrelog rbac rotate-keycommand that re-encrypts in placeAcceptance criteria
WyrelogKeyProviderinterface and two concrete backends land behind build flagsclose()and asserts no 32-byte key remainsTHIRD_PARTY_NOTICES.mdpresent and CI verifies it is updated when dependencies changeReferences