]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: implement keyfile auth for ssh disks with nbdkit
authorJonathon Jongsma <jjongsma@redhat.com>
Thu, 22 Dec 2022 22:56:47 +0000 (16:56 -0600)
committerJonathon Jongsma <jjongsma@redhat.com>
Tue, 19 Sep 2023 19:28:50 +0000 (14:28 -0500)
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@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
src/conf/domain_conf.c
src/conf/storage_source_conf.c
src/conf/storage_source_conf.h
src/qemu/qemu_nbdkit.c
tests/qemunbdkitdata/disk-network-ssh-key.args.disk0 [new file with mode: 0644]
tests/qemunbdkitdata/disk-network-ssh.args.disk2 [new file with mode: 0644]
tests/qemunbdkittest.c
tests/qemuxml2argvdata/disk-network-ssh-key.xml [new file with mode: 0644]

index 2eec9177dac99ff044f518abe858d24d139c37b7..c23dda673e9ef455d63201bb4d2e61e833cea43c 100644 (file)
@@ -7219,10 +7219,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;
@@ -22211,8 +22219,18 @@ 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");
+
+            virBufferEscapeString(childBuf, " username='%s'", src->ssh_user);
+            virBufferEscapeString(childBuf, " keyfile='%s'", src->ssh_keyfile);
+
+            virBufferAddLit(childBuf, "/>\n");
+        }
+    }
 }
 
 
index 0a39779d52d0998f92bb9746be13c339602a0a93..67d50af074982e7403bf616389827e327669c965 100644 (file)
@@ -898,6 +898,7 @@ virStorageSourceCopy(const virStorageSource *src,
     def->ssh_host_key_check_disabled = src->ssh_host_key_check_disabled;
     def->ssh_user = g_strdup(src->ssh_user);
     def->ssh_known_hosts_file = g_strdup(src->ssh_known_hosts_file);
+    def->ssh_keyfile = g_strdup(src->ssh_keyfile);
 
     def->nfs_user = g_strdup(src->nfs_user);
     def->nfs_group = g_strdup(src->nfs_group);
@@ -1177,6 +1178,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);
index a2b2244844bff2bca5d5f2893a6b15e93c6ba946..3b6e628e2175bd2ddad3c77d786c5412202a5dfb 100644 (file)
@@ -408,12 +408,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
index afac71e21a06358cffcae96526d76734a549e42d..0a6c7962b0fc80f037a084628e1741a592e9af10 100644 (file)
@@ -1049,8 +1049,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)
@@ -1171,6 +1175,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;
@@ -1256,6 +1264,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 (file)
index 0000000..0b52bfe
--- /dev/null
@@ -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 (file)
index 0000000..e269a34
--- /dev/null
@@ -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
index a51b287f34ad9ac2c666a76b132ad70d7c4045d4..559196a1cdf28fbb0f61dea0ffbf5d8317116105 100644 (file)
@@ -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 (file)
index 0000000..81b9223
--- /dev/null
@@ -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>