Repository navigation
Conversation
The keytab_loader option runs a program with a memfd for its output and watches its exit through a pidfd from the event loop; close_range closes the descriptors the program must not inherit. Without the first two the option is rejected. Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
keytab_loader names a program that produces the service's keytab: cred_store = keytab:MEMORY:<name> keytab_loader = /usr/libexec/kuipa-unseal --memfd The value is an absolute path and arguments, split on blanks without a shell. The service must use a MEMORY keytab, and services sharing one must name the same loader. Platforms without memfd_create and pidfd_open reject the option. gp_service_get_keytab() returns the keytab element of a service's cred store, which setup_krb5_creds_handle() looked up inline before. Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
A service with keytab_loader gets its keys from a program instead of a keytab file, so they never touch a filesystem. GSS-Proxy runs the program with a memfd as file descriptor 3 and, when it exits with status 0, copies the keytab it wrote into the service's MEMORY keytab and closes the memfd. * Loaders run asynchronously: a pidfd in the event loop reports their exit, and a loader running over five minutes is killed. * A failing loader is retried with exponential backoff (5 seconds up to 10 minutes); the keys loaded before stay in use meanwhile. * SIGHUP runs every loader again; a keytab no longer used by any service is emptied and released. * While a loader is configured the process is not dumpable, keeping the keys out of core dumps. The keytab name never changes, because credentials exported to clients refer to it by name and resolve it again when imported. Its contents are therefore replaced in place. Removing an entry from a MEMORY keytab frees it under any thread iterating over the keytab, so workers now hold a read lock around each request, and old entries are removed only when the main thread gets the write lock without waiting. When workers are busy the new keys are added at once and the old ones removed on a later attempt, so a request never misses a key. MIT destroys a MEMORY keytab when its last handle is closed, so each loader keeps one open for as long as it exists. Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
t_kt_loader "unseals" a keytab sealed by XORing each byte and writes it to file descriptor 3, or fails with status 75 while a given file exists, as kuipa-unseal does when no server can unseal. The sealed file is not a usable keytab, so gssproxy gets the keys only through the loader. t_keytab_loader.py checks the initial load, the re-run on SIGHUP, a failing loader (initiating as the service fails: there is no fallback to another keytab), the retry once it succeeds, and that a failing re-run keeps the keys loaded before. Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
The keytab_loader change is submitted as gssapi/gssproxy#135: the memfd loader into a MEMORY keytab, SIGHUP reload, retry with backoff, and core dumps disabled while a loader is configured. TODO keeps it open until it merges, and spells out what kuipa protect then does with it. Signed-off-by: Alexander Bokovoy <ab@vda.li>
simo5
left a comment
There was a problem hiding this comment.
On the surface this looks good, but is there any reason why the keytab is not simply returned via stdout (ie over a simple pipe)?
The memfd dance is cool and everything, but also quite unnecessary and adds complexity that doesn't seem really necessary given the child is spawn each time a keytab needs to be loaded.
|
The only reason to use memfd is to enforce secure memory that is guaranteed not to be backed by the file system. |
as fvar as I know pipes are never filesystem backed ... I guess they could be swapped in some rare cases, but then the solution is to simply use encrypted swap IMO. If it is not too much of a problem I would prefer to avoid the memfd additional complexity in this case. |
|
Thanks. I'll look at it tomorrow, too late tonight. :) |
|
With a pipe we'd have to buffer the bytes in the event loop and parse the MIT keytab format ourselves (v2/v3 framing with the total-length/per-entry-length fields), then krb5_kt_add_entry. From experiment:
|
Add a way to read keytab from a dynamic source.
A service with
keytab_loadergets its keys from a program instead of a keytab file, so they never touch a filesystem. GSS-Proxy runs the program with a memfd as file descriptor 3 and, when it exits with status 0, copies the keytab it wrote into the service's MEMORY keytab and closes the memfd.This allows to handle encrypted keytabs or keytabs protected by NBDE-like configurations.
Test keytab loader is providing a sample implementation that uses a XORed file. It also accepts a file that, if exists, causes a failure simulation.
Assisted-by: Claude Code (Opus 5.5)