[libvirt PATCH v6 32/36] qemu: implement keyfile auth for ssh disks with nbdkit

Jonathon Jongsma jjongsma at redhat.com
Thu Jul 20 22:19:59 UTC 2023


For ssh disks that are served by nbdkit, we can support logging in with
an ssh key file. Pass the path to the configured key file and the
username to the nbdkit process.

Signed-off-by: Jonathon Jongsma <jjongsma at redhat.com>
---
 src/conf/domain_conf.c                        | 32 ++++++++++++++----
 src/conf/storage_source_conf.c                |  1 +
 src/conf/storage_source_conf.h                |  5 ++-
 src/qemu/qemu_nbdkit.c                        | 15 +++++++--
 .../disk-network-ssh-key.args.disk0           |  9 +++++
 .../disk-network-ssh.args.disk2               |  9 +++++
 tests/qemunbdkittest.c                        |  1 +
 .../qemuxml2argvdata/disk-network-ssh-key.xml | 33 +++++++++++++++++++
 8 files changed, 94 insertions(+), 11 deletions(-)
 create mode 100644 tests/qemunbdkitdata/disk-network-ssh-key.args.disk0
 create mode 100644 tests/qemunbdkitdata/disk-network-ssh.args.disk2
 create mode 100644 tests/qemuxml2argvdata/disk-network-ssh-key.xml

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 6420231e5c..08cf1be656 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -7248,10 +7248,18 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node,
             return -1;
         }
     }
-    if (src->protocol == VIR_STORAGE_NET_PROTOCOL_SSH &&
-        (tmpnode = virXPathNode("./knownHosts", ctxt))) {
-        if (!(src->ssh_known_hosts_file = virXMLPropStringRequired(tmpnode, "path")))
-            return -1;
+    if (src->protocol == VIR_STORAGE_NET_PROTOCOL_SSH) {
+        if ((tmpnode = virXPathNode("./knownHosts", ctxt))) {
+            if (!(src->ssh_known_hosts_file = virXMLPropStringRequired(tmpnode, "path")))
+                return -1;
+        }
+        if ((tmpnode = virXPathNode("./identity", ctxt))) {
+            if (!(src->ssh_user = virXMLPropStringRequired(tmpnode, "username")))
+                return -1;
+
+            if (!(src->ssh_keyfile = virXMLPropStringRequired(tmpnode, "keyfile")))
+                return -1;
+        }
     }
 
     return 0;
@@ -22164,8 +22172,20 @@ virDomainDiskSourceFormatNetwork(virBuffer *attrBuf,
     if (src->timeout)
         virBufferAsprintf(childBuf, "<timeout seconds='%llu'/>\n", src->timeout);
 
-    if (src->protocol == VIR_STORAGE_NET_PROTOCOL_SSH && src->ssh_known_hosts_file)
-        virBufferEscapeString(childBuf, "<knownHosts path='%s'/>\n", src->ssh_known_hosts_file);
+    if (src->protocol == VIR_STORAGE_NET_PROTOCOL_SSH) {
+        if (src->ssh_known_hosts_file)
+            virBufferEscapeString(childBuf, "<knownHosts path='%s'/>\n", src->ssh_known_hosts_file);
+        if (src->ssh_keyfile) {
+            virBufferAddLit(childBuf, "<identity");
+
+            if (src->ssh_user)
+                virBufferEscapeString(childBuf, " username='%s'", src->ssh_user);
+            if (src->ssh_keyfile)
+                virBufferEscapeString(childBuf, " keyfile='%s'", src->ssh_keyfile);
+
+            virBufferAddLit(childBuf, "/>\n");
+        }
+    }
 }
 
 
diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c
index 3468deb760..5074d6b219 100644
--- a/src/conf/storage_source_conf.c
+++ b/src/conf/storage_source_conf.c
@@ -1171,6 +1171,7 @@ virStorageSourceClear(virStorageSource *def)
 
     VIR_FREE(def->ssh_user);
     VIR_FREE(def->ssh_known_hosts_file);
+    VIR_FREE(def->ssh_keyfile);
 
     VIR_FREE(def->nfs_user);
     VIR_FREE(def->nfs_group);
diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h
index 8a9c7d07e2..8c805664af 100644
--- a/src/conf/storage_source_conf.h
+++ b/src/conf/storage_source_conf.h
@@ -406,12 +406,11 @@ struct _virStorageSource {
 
     bool hostcdrom; /* backing device is a cdrom */
 
-    /* passthrough variables for the ssh driver which we don't handle properly */
-    /* these must not be used apart from formatting the output JSON in the qemu driver */
+    /* ssh variables */
     char *ssh_user;
     bool ssh_host_key_check_disabled;
-    /* additional ssh variables */
     char *ssh_known_hosts_file;
+    char *ssh_keyfile;
 
     /* nfs_user and nfs_group store the strings passed in by the user for NFS params.
      * nfs_uid and nfs_gid represent the converted/looked up ID numbers which are used
diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c
index b4f5b2178c..4bebabf799 100644
--- a/src/qemu/qemu_nbdkit.c
+++ b/src/qemu/qemu_nbdkit.c
@@ -1038,8 +1038,12 @@ qemuNbdkitProcessBuildCommandSSH(qemuNbdkitProcess *proc,
     if (proc->source->auth) {
         if (qemuNbdkitProcessBuildCommandAuth(proc->source->auth, cmd) < 0)
             return -1;
-    } else if (proc->source->ssh_user) {
-        virCommandAddArgPair(cmd, "user", proc->source->ssh_user);
+    } else {
+        if (proc->source->ssh_keyfile)
+            virCommandAddArgPair(cmd, "identity", proc->source->ssh_keyfile);
+
+        if (proc->source->ssh_user)
+            virCommandAddArgPair(cmd, "user", proc->source->ssh_user);
     }
 
     if (proc->source->ssh_host_key_check_disabled)
@@ -1160,6 +1164,10 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc,
     if (qemuExtDeviceLogCommand(driver, vm, cmd, "nbdkit") < 0)
         goto error;
 
+    if (proc->source->ssh_keyfile &&
+        qemuSecurityDomainSetPathLabel(driver, vm, proc->source->ssh_keyfile, false) < 0)
+        goto error;
+
     if (proc->source->ssh_known_hosts_file &&
         qemuSecurityDomainSetPathLabel(driver, vm, proc->source->ssh_known_hosts_file, false) < 0)
         goto error;
@@ -1245,6 +1253,9 @@ qemuNbdkitProcessStop(qemuNbdkitProcess *proc,
     if (proc->source->ssh_known_hosts_file)
         qemuSecurityDomainRestorePathLabel(driver, vm, proc->source->ssh_known_hosts_file);
 
+    if (proc->source->ssh_keyfile)
+        qemuSecurityDomainRestorePathLabel(driver, vm, proc->source->ssh_keyfile);
+
     if (proc->pid < 0)
         return 0;
 
diff --git a/tests/qemunbdkitdata/disk-network-ssh-key.args.disk0 b/tests/qemunbdkitdata/disk-network-ssh-key.args.disk0
new file mode 100644
index 0000000000..0b52bfe0fb
--- /dev/null
+++ b/tests/qemunbdkitdata/disk-network-ssh-key.args.disk0
@@ -0,0 +1,9 @@
+nbdkit \
+--unix /tmp/statedir-0/nbdkit-test-disk-0.socket \
+--foreground ssh \
+host=example.org \
+port=2222 \
+path=test.img \
+identity=/path/to/id_rsa \
+user=myuser \
+known-hosts=/path/to/ssh_known_hosts
diff --git a/tests/qemunbdkitdata/disk-network-ssh.args.disk2 b/tests/qemunbdkitdata/disk-network-ssh.args.disk2
new file mode 100644
index 0000000000..e269a34351
--- /dev/null
+++ b/tests/qemunbdkitdata/disk-network-ssh.args.disk2
@@ -0,0 +1,9 @@
+nbdkit \
+--unix /tmp/statedir-2/nbdkit-test-disk-2.socket \
+--foreground ssh \
+host=example.org \
+port=2222 \
+path=test2.img \
+identity=/path/to/id_rsa \
+user=myuser \
+known-hosts=/path/to/ssh_known_hosts
diff --git a/tests/qemunbdkittest.c b/tests/qemunbdkittest.c
index a51b287f34..559196a1cd 100644
--- a/tests/qemunbdkittest.c
+++ b/tests/qemunbdkittest.c
@@ -299,6 +299,7 @@ mymain(void)
     DO_TEST("disk-network-source-curl", QEMU_NBDKIT_CAPS_PLUGIN_CURL);
     DO_TEST("disk-network-ssh", QEMU_NBDKIT_CAPS_PLUGIN_SSH);
     DO_TEST("disk-network-ssh-password", QEMU_NBDKIT_CAPS_PLUGIN_SSH);
+    DO_TEST("disk-network-ssh-key", QEMU_NBDKIT_CAPS_PLUGIN_SSH);
 
  cleanup:
     qemuTestDriverFree(&driver);
diff --git a/tests/qemuxml2argvdata/disk-network-ssh-key.xml b/tests/qemuxml2argvdata/disk-network-ssh-key.xml
new file mode 100644
index 0000000000..81b92231fa
--- /dev/null
+++ b/tests/qemuxml2argvdata/disk-network-ssh-key.xml
@@ -0,0 +1,33 @@
+<domain type='kvm'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <disk type='network' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source protocol='ssh' name='test.img'>
+        <host name='example.org' port='2222'/>
+        <timeout seconds='1234'/>
+        <readahead size='1024'/>
+        <identity username='myuser' keyfile='/path/to/id_rsa'/>
+        <knownHosts path="/path/to/ssh_known_hosts"/>
+      </source>
+      <target dev='vda' bus='virtio'/>
+    </disk>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
-- 
2.41.0



More information about the libvir-list mailing list