Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow connect to use configured TLS keys #2532

Merged
merged 11 commits into from
Oct 28, 2024
24 changes: 18 additions & 6 deletions Documentation/nvme-connect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ SYNOPSIS
[--keep-alive-tmo=<#> | -k <#>]
[--reconnect-delay=<#> | -c <#>]
[--ctrl-loss-tmo=<#> | -l <#>] [--tos=<#> | -T <#>]
[--keyring=<#>] [--tls_key=<#>]
[--keyring=<keyring>] [--tls-key=<tls-key>]
[--tls-key-identity=<identity>]
[--duplicate-connect | -D] [--disable-sqflow ]
[--hdr-digest | -g] [--data-digest | -G] [--tls]
[--concat] [--dump-config | -O] [--application=<id>]
Expand Down Expand Up @@ -151,11 +152,22 @@ OPTIONS
--tos=<#>::
Type of service for the connection (TCP)

--keyring=<#>::
Keyring for TLS key lookup.

--tls_key=<#>::
TLS key for the connection (TCP).
--keyring=<keyring>::
Keyring for TLS key lookup, either the key id or the keyring name.

--tls-key=<tls-key>::
TLS key for the connection (TCP), either the TLS key in
interchange format or the key id. It's strongly recommended not
to provide the TLS key via the comamnd line due to security
concerns. Instead in production situation, the key should be
loaded into the keystore with 'nvme tls --import' and only the
'--tls' options used. The kernel will select the matching key.

--tls-key-identity=<identity>::
The identity used for the tls-key. If none is provided the
tls-key provided via the comamnd line is considered a
configuration key and a derive key will be loaded into the
keyring.

-D::
--duplicate-connect::
Expand Down
6 changes: 6 additions & 0 deletions Documentation/nvme-gen-tls-key.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ SYNOPSIS
[--identity=<id-vers> | -I <id-vers>]
[--secret=<secret> | -s <secret>]
[--insert | -i]
[--keyfile=<keyfile> | -f <keyfile>]
[--output-format=<fmt> | -o <fmt>] [--verbose | -v]

DESCRIPTION
Expand Down Expand Up @@ -81,6 +82,11 @@ OPTIONS
Insert the resulting TLS key into the keyring without printing out
the key in PSK interchange format.

-f <keyfile>
--keyfile=<keyfile>
Append the resulting TLS key to keyfile. This command line option is
depending on --insert.

-o <fmt>::
--output-format=<fmt>::
Set the reporting format to 'normal', 'json' or 'binary'. Only one
Expand Down
118 changes: 106 additions & 12 deletions fabrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@
static const char *nvmf_ctrl_loss_tmo = "controller loss timeout period in seconds";
static const char *nvmf_fast_io_fail_tmo = "fast I/O fail timeout (default off)";
static const char *nvmf_tos = "type of service";
static const char *nvmf_keyring = "Keyring for TLS key lookup";
static const char *nvmf_tls_key = "TLS key to use";
static const char *nvmf_keyring = "Keyring for TLS key lookup (key id or keyring name)";
static const char *nvmf_tls_key = "TLS key to use (key id or key in interchange format)";
static const char *nvmf_tls_key_legacy = "TLS key to use (key id)";
static const char *nvmf_tls_key_identity = "TLS key identity";
static const char *nvmf_dup_connect = "allow duplicate connections between same transport host and subsystem port";
static const char *nvmf_disable_sqflow = "disable controller sq flow control (default false)";
static const char *nvmf_hdr_digest = "enable transport protocol header digest (TCP transport)";
Expand All @@ -103,6 +105,9 @@
OPT_STRING("hostnqn", 'q', "STR", &hostnqn, nvmf_hostnqn), \
OPT_STRING("hostid", 'I', "STR", &hostid, nvmf_hostid), \
OPT_STRING("dhchap-secret", 'S', "STR", &hostkey, nvmf_hostkey), \
OPT_STRING("keyring", 0, "STR", &keyring, nvmf_keyring), \
OPT_STRING("tls-key", 0, "STR", &tls_key, nvmf_tls_key), \
OPT_STRING("tls-key-identity", 0, "STR", &tls_key_identity, nvmf_tls_key_identity), \

Check failure on line 110 in fabrics.c

View workflow job for this annotation

GitHub Actions / checkpatch review

WARNING: line length of 102 exceeds 100 columns
OPT_INT("nr-io-queues", 'i', &c.nr_io_queues, nvmf_nr_io_queues), \
OPT_INT("nr-write-queues", 'W', &c.nr_write_queues, nvmf_nr_write_queues), \
OPT_INT("nr-poll-queues", 'P', &c.nr_poll_queues, nvmf_nr_poll_queues), \
Expand All @@ -112,8 +117,7 @@
OPT_INT("ctrl-loss-tmo", 'l', &c.ctrl_loss_tmo, nvmf_ctrl_loss_tmo), \
OPT_INT("fast_io_fail_tmo", 'F', &c.fast_io_fail_tmo, nvmf_fast_io_fail_tmo),\
OPT_INT("tos", 'T', &c.tos, nvmf_tos), \
OPT_INT("keyring", 0, &c.keyring, nvmf_keyring), \
OPT_INT("tls_key", 0, &c.tls_key, nvmf_tls_key), \
OPT_INT("tls_key", 0, &c.tls_key, nvmf_tls_key_legacy), \
OPT_FLAG("duplicate-connect", 'D', &c.duplicate_connect, nvmf_dup_connect), \
OPT_FLAG("disable-sqflow", 0, &c.disable_sqflow, nvmf_disable_sqflow), \
OPT_FLAG("hdr-digest", 'g', &c.hdr_digest, nvmf_hdr_digest), \
Expand Down Expand Up @@ -407,7 +411,8 @@
{
char *transport = NULL, *traddr = NULL, *trsvcid = NULL;
char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL;
char *subsysnqn = NULL;
char *subsysnqn = NULL, *keyring = NULL, *tls_key = NULL;
char *tls_key_identity = NULL;
char *ptr, **argv, *p, line[4096];
int argc, ret = 0;
unsigned int verbose = 0;
Expand Down Expand Up @@ -681,6 +686,8 @@
char *subsysnqn = NVME_DISC_SUBSYS_NAME;
char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL;
char *transport = NULL, *traddr = NULL, *trsvcid = NULL;
char *keyring = NULL, *tls_key = NULL;
char *tls_key_identity = NULL;
char *config_file = PATH_NVMF_CONFIG;
_cleanup_free_ char *hnqn = NULL;
_cleanup_free_ char *hid = NULL;
Expand Down Expand Up @@ -886,15 +893,93 @@
return ret;
}

static int nvme_connect_config(nvme_root_t r, const char *hostnqn, const char *hostid,
const struct nvme_fabrics_config *cfg)
{
const char *hnqn, *hid;
const char *transport;
nvme_host_t h;
nvme_subsystem_t s;
nvme_ctrl_t c, _c;
int ret = 0, err;

nvme_for_each_host(r, h) {
nvme_for_each_subsystem(h, s) {
hnqn = nvme_host_get_hostnqn(h);
if (hostnqn && hnqn && strcmp(hostnqn, hnqn))
continue;
hid = nvme_host_get_hostid(h);
if (hostid && hid && strcmp(hostid, hid))
continue;

nvme_subsystem_for_each_ctrl_safe(s, c, _c) {
transport = nvme_ctrl_get_transport(c);

/* ignore none fabric transports */
if (strcmp(transport, "tcp") &&
strcmp(transport, "rdma") &&
strcmp(transport, "fc"))
continue;

err = nvmf_connect_ctrl(c);
if (err) {
if (errno == ENVME_CONNECT_ALREADY)
continue;

fprintf(stderr,
"failed to connect to hostnqn=%s,nqn=%s,%s\n",
nvme_host_get_hostnqn(h),
nvme_subsystem_get_name(s),
nvme_ctrl_get_address(c));

if (!ret)
ret = err;
}
}
}
}

return ret;
}

static void nvme_parse_tls_args(const char *keyring, const char *tls_key,
const char *tls_key_identity,
struct nvme_fabrics_config *cfg, nvme_ctrl_t c)
{
if (keyring) {
char *endptr;
long id = strtol(keyring, &endptr, 0);

if (endptr != keyring)
cfg->keyring = id;
else
nvme_ctrl_set_keyring(c, keyring);
}

if (tls_key_identity)
nvme_ctrl_set_tls_key_identity(c, tls_key_identity);

if (tls_key) {
char *endptr;
long id = strtol(tls_key, &endptr, 0);

if (endptr != tls_key)
cfg->tls_key = id;
else
nvme_ctrl_set_tls_key(c, tls_key);
}
}

int nvmf_connect(const char *desc, int argc, char **argv)
{
char *subsysnqn = NULL;
char *transport = NULL, *traddr = NULL;
char *trsvcid = NULL, *hostnqn = NULL, *hostid = NULL;
char *hostkey = NULL, *ctrlkey = NULL;
char *hostkey = NULL, *ctrlkey = NULL, *keyring = NULL;
char *tls_key = NULL, *tls_key_identity = NULL;
_cleanup_free_ char *hnqn = NULL;
_cleanup_free_ char *hid = NULL;
char *config_file = PATH_NVMF_CONFIG;
char *config_file = NULL;
char *context = NULL;
unsigned int verbose = 0;
_cleanup_nvme_root_ nvme_root_t r = NULL;
Expand All @@ -905,7 +990,6 @@
struct nvme_fabrics_config cfg = { 0 };
char *format = "normal";


NVMF_ARGS(opts, cfg,
OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey),
OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file),
Expand All @@ -926,6 +1010,9 @@
return ret;
}

if (config_file && strcmp(config_file, "none"))
goto do_connect;

if (!subsysnqn) {
fprintf(stderr,
"required argument [--nqn | -n] not specified\n");
Expand All @@ -947,9 +1034,7 @@
}
}

if (!strcmp(config_file, "none"))
config_file = NULL;

do_connect:
log_level = map_log_level(verbose, quiet);

r = nvme_create_root(stderr, log_level);
Expand Down Expand Up @@ -986,6 +1071,9 @@
if (!trsvcid)
trsvcid = nvmf_get_default_trsvcid(transport, false);

if (config_file)
return nvme_connect_config(r, hostnqn, hostid, &cfg);

struct tr_config trcfg = {
.subsysnqn = subsysnqn,
.transport = transport,
Expand All @@ -1008,9 +1096,12 @@
errno = ENOMEM;
goto out_free;
}

if (ctrlkey)
nvme_ctrl_set_dhchap_key(c, ctrlkey);

nvme_parse_tls_args(keyring, tls_key, tls_key_identity, &cfg, c);

errno = 0;
ret = nvmf_add_ctrl(h, c, &cfg);
if (ret)
Expand Down Expand Up @@ -1233,6 +1324,7 @@
_cleanup_free_ char *hnqn = NULL;
_cleanup_free_ char *hid = NULL;
char *hostkey = NULL, *ctrlkey = NULL;
char *keyring = NULL, *tls_key = NULL, *tls_key_identity = NULL;
char *config_file = PATH_NVMF_CONFIG;
unsigned int verbose = 0;
_cleanup_nvme_root_ nvme_root_t r = NULL;
Expand Down Expand Up @@ -1322,9 +1414,11 @@
nvme_strerror(errno));
return -errno;
}
nvmf_update_config(c, &cfg);
if (ctrlkey)
nvme_ctrl_set_dhchap_key(c, ctrlkey);
nvme_parse_tls_args(keyring, tls_key, tls_key_identity, &cfg, c);

nvmf_update_config(c, &cfg);
}

if (update_config)
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ endforeach
udev_files = [
'65-persistent-net-nbft.rules',
'70-nvmf-autoconnect.rules',
'70-nvmf-keys.rules',
'71-nvmf-netapp.rules',
]

Expand Down
Loading
Loading