Skip to content
This repository was archived by the owner on Oct 1, 2026. It is now read-only.

NFS mTLS client identity management - #163

Merged
chucklever merged 3 commits into
mainfrom
nfs-mtls-identity
Sep 16, 2026
Merged

chucklever merged 3 commits into
mainfrom
nfs-mtls-identity

Conversation

@chucklever

Copy link
Copy Markdown
Member

tlshd links the .nfs and .nfsd keyrings into its session keyring only at
startup and on SIGHUP. The kernel creates each keyring when nfs.ko or
nfsd.ko loads, and tlshd starts before remote-fs-pre.target, so on a
freshly booted client a handshake naming a key on .nfs fails with EACCES
until an administrator sends SIGHUP. The startup link also hands every
NFS credential in the keyring to the long-lived tlshd parent and to
every handshake child, whether or not that handshake uses them.

This series moves the link to per-handshake instead: a handshake child
links .nfs or .nfsd into its own process keyring just before it reads
its certificate, by which point the keyring already exists, so startup
ordering no longer matters.

nfstlskey provisions NFS mTLS client identities onto that same .nfs
keyring, in place of an administrator loading keys by hand and pasting
boot-variable, opaque serials onto mount command lines. It locates the
keyring through the nfs_keyring key type where available, and on a
kernel without that type falls back to the same /proc/keys scan tlshd
itself uses to find the keyring the kernel creates at module load.

tlshd links the .nfs and .nfsd keyrings into its session keyring
when it starts and when it reloads its configuration. The kernel
creates each keyring when the owning module loads, so a tlshd that
starts before nfs.ko or nfsd.ko is loaded never possesses the
keyring, and a handshake that names a key on it fails with EACCES
until the administrator sends tlshd a SIGHUP. tlshd starts before
remote-fs-pre.target, so on a freshly booted NFS client that is the
common ordering. The startup link also hands possession of every
NFS credential to the long-lived parent and to every handshake
child, whether or not the handshake uses them.

The handshake upcall already carries a keyring serial that the
kernel links into the process keyring of the child that accepts
the request. That link is private to the child and is released
when it exits. Give handshakes whose request names no keyring the
same treatment: link .nfs into the process keyring of a client
handshake child, and .nfsd into that of a server handshake child,
just before the child reads its certificate from the keyring. By
then the keyring exists, since the kernel handed out serials on it,
so the startup ordering no longer matters. The .nvme keyring keeps
its startup link.

The child also links the keyring the request named into its
session keyring and unlinks it when the handshake is done. The
session keyring is shared with the parent and with every sibling
child, so that link grants possession beyond the one handshake
for as long as it lasts. The kernel's process keyring link has
been present since the handshake upcall was introduced, so drop
the session keyring link and unlink. The server PSK callbacks
find the peer's key by description, and a search of the session
keyring does not reach the process keyring, so search the process
keyring first.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
An xprtsec=mtls mount names its client certificate and private key
by keyring serial. The administrator loads both into a keyring by
hand, reads the serials back, and pastes them onto the mount command
line, where they are opaque, differ on every boot, and are easy to
transpose. The keys also sit wherever the administrator put them,
readable by whatever can reach that keyring.

Add nfstlskey, which provisions a named identity onto the .nfs keyring
of the caller's network namespace as a pair of "user" keys readable by
possessors only. It converts PEM input to DER, refuses a certificate
chain or a key that does not match the certificate, prints the mount
options that select an identity, and replaces the key material of one
in place so that a renewed certificate reaches mounts without a
remount. nfstlskey(8) documents the tool and its keyring layout.

The tool locates the namespace keyring through the nfs_keyring key
type. A kernel without that type has a single .nfs keyring, created
at nfs module load since v6.17, that tlshd already links into its
session keyring. When the nfs_keyring request fails with ENOKEY
after nfs.ko is loaded, find that keyring by scanning /proc/keys,
the way tlshd does, and continue with the same trust check, link,
and key management. Only the kernel can create a keyring whose name
begins with a period, so the scan cannot be answered by a keyring
another process planted. Report on stderr that the shared keyring is
in use, since identities on it are visible to mounts in every
network namespace.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
tlshd_x509_retrieve_key_cb() logs "Selecting x509.certificate from
conf file" whenever it hands GnuTLS the non-PQ certificate. A
handshake request that carries certificate and private key serials
loads that certificate from the keyring, so on every keyring-based
handshake the line names the wrong source, right after the line that
reports the keyring read.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Sep 16, 2026
@chucklever
chucklever merged commit bbcb843 into main Sep 16, 2026
13 checks passed
@chucklever
chucklever deleted the nfs-mtls-identity branch September 16, 2026 20:37
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant