nvme-keysd(8)
=============

NAME
----
nvme-keysd - NVMe/TCP TLS key provisioning daemon

SYNOPSIS
--------
[verse]
'nvme-keysd' [--config=<FILE>] [--fabrics-config=<FILE>]
		[--creds-dir=<DIR>] [--kmip-test-addr=<PATH>]
		[--should-start] [--debug] [--help]

DESCRIPTION
-----------
nvme-keysd puts the TLS pre-shared keys (PSKs) used by NVMe/TCP into the
kernel's .nvme keyring, before a connection needs them. The kernel then
finds the key there when 'nvme connect' or nvme-discoverd connects with
TLS.

Which key belongs to which host and subsystem is configured in the
shared NVMe-oF fabrics configuration, see nvme-fabrics.conf(5).

This is a technology preview.

KEYS
----
nvme-keysd imports every entry of the fabrics configuration that has
'tls-key-source = systemd-creds' or 'tls-key-source = kmip'. With
'systemd-creds', 'tls-key' is the name of a systemd credential. The
credential holds the PSK in the PSK interchange format
('NVMeTLSkey-1:<hmac>:<base64>:'), as created by 'nvme keys
gen-tls-psk'.

nvme-keysd puts the PSK in the keyring named by 'keyring' (default
'.nvme'). The key identity is built from the host NQN and the subsystem
NQN, as 'nvme connect' does. A key that is already there is not written
again. Any other key for the same host NQN and subsystem NQN is revoked,
so that the kernel finds only one key for the pair.

Without a 'kmip' entry, nvme-keysd imports the keys and exits. With a
'kmip' entry, it keeps running: see KMIP. nvme-keysd never revokes a key
because its entry was removed from the configuration.

The unit does not start when no entry of the fabrics configuration has
a 'tls-key-source' other than 'inline'. In that case, nvme-keysd does not
run, and the unit does not load the nvme_keyring module.

CREDENTIALS
-----------
Each credential is a file in @SYSCONFDIR@/nvme/creds/, encrypted with
systemd-creds(1). The directory is installed with mode 0700. The file
name is the credential name. nvme-keysd decrypts the file through
systemd-creds, which checks that the name in the credential is the file
name. When '--name' is not given, systemd-creds takes the name from the
output file name:

	# systemd-creds encrypt psk.txt @SYSCONFDIR@/nvme/creds/vol1-psk

and in nvme-fabrics.conf:

	[Subsystem]
	nqn        = nqn.2024-01.com.example:storage.vol1
	controller = transport=tcp;traddr=192.0.2.10;trsvcid=4420
	tls        = true
	tls-key-source = systemd-creds
	tls-key    = vol1-psk

After adding or changing credentials, restart nvme-keysd to import
them:

	# systemctl restart nvme-keysd

nvme-keysd logs an error for a credential that it cannot decrypt, and
imports the other keys.

nvme-keysd needs systemd 257 or later.

KMIP
----
With 'tls-key-source = kmip:<name>', nvme-keysd gets the PSK from a key
management server (KMS) that supports KMIP 1.4. '<name>' is a
'[kmip:<name>]' section of nvme-keysd.conf. When only one KMS is
configured, 'tls-key-source = kmip' is enough. 'tls-key' is the Name of
the key on the KMS.

The key on the KMS is one of:

- Secret Data that holds the PSK in the PSK interchange format.
- A Symmetric Key of 32 bytes (SHA-256) or 48 bytes (SHA-384).

Only a key in the Active state is used. Two Active keys with the same
Name are an error.

nvme-keysd itself has no network access. For privilege separation, a
helper process with no privileges handles all communication with the
KMS, over TLS. A client certificate is used when one is configured.
The helper logs its errors in the journal, under the identifier
nvme-keysd-kmip.

The servers of a KMS are nodes of one cluster, and hold the same keys.
They are tried in order, until one answers. Different KMSes are asked
in parallel.

nvme-keysd does not delay the boot for a KMS. The services that start
after nvme-keysd find the keys from systemd credentials in the keyring,
but a KMIP key can come later. nvme-keysd keeps running and gets the
KMIP keys in the background. When it cannot get a key, it tries again
after 5 seconds, then after twice the previous delay, up to 5 minutes.
A connection that needs a KMIP key can therefore start before the key
is in the keyring. nvme-discoverd connects again later. A single 'nvme
connect' does not.

Setup example. The client private key is a systemd credential in
@SYSCONFDIR@/nvme/creds/kmip/. systemd gives it to the helper as
'kmip_<file>', so '--name' must be 'kmip_' and the file name:

	# systemd-creds encrypt --name=kmip_my-client-key client-key.pem \
		@SYSCONFDIR@/nvme/creds/kmip/my-client-key

The CA and the client certificate are not secret. They must be readable
by any user, because the helper runs without privileges. In
nvme-keysd.conf:

	[kmip:my-kms]
	server      = kms1.example.com
	server      = kms2.example.com
	ca          = @SYSCONFDIR@/nvme/kmip/ca.pem
	client-cert = @SYSCONFDIR@/nvme/kmip/client.pem
	client-key  = my-client-key

and in nvme-fabrics.conf:

	[Subsystem]
	nqn        = nqn.2024-01.com.example:storage.vol1
	controller = transport=tcp;traddr=192.0.2.10;trsvcid=4420
	tls        = true
	tls-key-source = kmip:my-kms
	tls-key    = my-vol1-psk

OPTIONS
-------
-c <FILE>::
--config=<FILE>::
	Use <FILE> instead of @SYSCONFDIR@/nvme/nvme-keysd.conf.

--fabrics-config=<FILE>::
	Read the fabrics configuration from <FILE> instead of
	@SYSCONFDIR@/nvme/nvme-fabrics.conf.

--creds-dir=<DIR>::
	Read the encrypted credentials from <DIR> instead of
	@SYSCONFDIR@/nvme/creds.

--kmip-test-addr=<PATH>::
	Connect to the nvme-keysd-kmip Varlink socket at <PATH> instead of
	@RUNDIR@/nvme/keysd/kmip. For tests.

--should-start::
	Exit with status 0 if an entry of the fabrics configuration has a
	'tls-key-source' other than 'inline', and with status 1 otherwise.
	The unit runs this check before it starts nvme-keysd.

-d::
--debug::
	Enable debug-level logging for both nvme-keysd and the libnvme
	calls it makes, overriding the configured debug-level.

-h::
--help::
	Print usage and exit.

CONFIGURATION
-------------
nvme-keysd.conf holds the daemon's own settings, in a '[Global]'
section, and the KMSes, in '[kmip:<name>]' sections:

	[Global]
	debug-level = info

'debug-level' (err, warn, info, or debug; default info) sets the log
threshold. '--debug' on the command line overrides it.

Each '[kmip:<name>]' section describes a KMS:

'server'::
	Host name or IP address. Required. Repeat it for each server of
	the cluster.
'port'::
	TCP port of the servers. Default 5696.
'ca'::
	CA certificate that signed the server certificates (PEM). Default:
	the system CAs.
'client-cert'::
	Client certificate (PEM). Requires 'client-key'.
'client-key'::
	File name of the client private key in
	@SYSCONFDIR@/nvme/creds/kmip/. Requires 'client-cert'.
'timeout'::
	Time limit for one server: connect, TLS handshake and requests.
	Default 10s. Each TCP connect fails after 3 seconds at most.

A missing file, or a missing key, keeps the default.

FILES
-----
@SYSCONFDIR@/nvme/nvme-keysd.conf::
	The daemon's own configuration; see CONFIGURATION.

@SYSCONFDIR@/nvme/nvme-keysd.conf.sample::
	A commented example of nvme-keysd.conf with every setting at its
	default. It is not read; copy it to nvme-keysd.conf to change a
	setting.

@SYSCONFDIR@/nvme/creds/::
	The encrypted credentials; see CREDENTIALS.

@SYSCONFDIR@/nvme/creds/kmip/::
	The encrypted client private keys for the KMSes; see KMIP.

SEE ALSO
--------
nvme-fabrics.conf(5)
systemd-creds(1)
nvme-discoverd(8)
nvme-connect(1)

NVME
----
Part of the nvme-user suite
