[libvirt PATCH v7 34/35] qemu: implement ssh-agent auth for ssh disks with nbdkit

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



It's not possible to use password-protected ssh keys directly with
libvirt because libvirt doesn't have any way to prompt a user for the
password. To accomodate password-protected key files, an administrator
can add these keys to an ssh agent and then configure the domain with
the path to the ssh-agent socket.

Note that this requires an administrator or management app to
configure the ssh-agent with an appropriate socket path and add the
necessary keys to it. In addition, it does not currently work with
selinux enabled. The ssh-agent socket would need a label that libvirt
would be allowed to access rather than unconfined_t.

Signed-off-by: Jonathon Jongsma <jjongsma@xxxxxxxxxx>
Reviewed-by: Peter Krempa <pkrempa@xxxxxxxxxx>
---
 src/conf/domain_conf.c                          | 14 ++++++++++++--
 src/conf/storage_source_conf.c                  |  2 ++
 src/conf/storage_source_conf.h                  |  1 +
 src/qemu/qemu_nbdkit.c                          | 10 ++++++++++
 .../disk-network-ssh-key.args.disk0             |  6 +++---
 .../disk-network-ssh-key.args.disk1             |  9 +++++++++
 tests/qemuxml2argvdata/disk-network-ssh-key.xml | 17 ++++++++++++++---
 7 files changed, 51 insertions(+), 8 deletions(-)
 create mode 100644 tests/qemunbdkitdata/disk-network-ssh-key.args.disk1

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 929e115bce..398f40d2be 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -7277,8 +7277,17 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node,
             if (!(src->ssh_user = virXMLPropStringRequired(tmpnode, "username")))
                 return -1;
 
-            if (!(src->ssh_keyfile = virXMLPropStringRequired(tmpnode, "keyfile")))
+            /* optional path to an ssh key file */
+            src->ssh_keyfile = virXMLPropString(tmpnode, "keyfile");
+
+            /* optional ssh-agent socket location */
+            src->ssh_agent = virXMLPropString(tmpnode, "agentsock");
+            if (!src->ssh_keyfile && !src->ssh_agent) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("element '%1$s' requires either 'keyfile' or 'agentsock' attribute"),
+                               tmpnode->name);
                 return -1;
+            }
         }
     }
 
@@ -22291,11 +22300,12 @@ virDomainDiskSourceFormatNetwork(virBuffer *attrBuf,
     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) {
+        if (src->ssh_keyfile || src->ssh_agent) {
             virBufferAddLit(childBuf, "<identity");
 
             virBufferEscapeString(childBuf, " username='%s'", src->ssh_user);
             virBufferEscapeString(childBuf, " keyfile='%s'", src->ssh_keyfile);
+            virBufferEscapeString(childBuf, " agentsock='%s'", src->ssh_agent);
 
             virBufferAddLit(childBuf, "/>\n");
         }
diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c
index ce9c1f66c2..cafa031dfe 100644
--- a/src/conf/storage_source_conf.c
+++ b/src/conf/storage_source_conf.c
@@ -897,6 +897,7 @@ virStorageSourceCopy(const virStorageSource *src,
     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->ssh_agent = g_strdup(src->ssh_agent);
 
     def->nfs_user = g_strdup(src->nfs_user);
     def->nfs_group = g_strdup(src->nfs_group);
@@ -1174,6 +1175,7 @@ virStorageSourceClear(virStorageSource *def)
     VIR_FREE(def->ssh_user);
     VIR_FREE(def->ssh_known_hosts_file);
     VIR_FREE(def->ssh_keyfile);
+    VIR_FREE(def->ssh_agent);
 
     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 8c805664af..061faa66cb 100644
--- a/src/conf/storage_source_conf.h
+++ b/src/conf/storage_source_conf.h
@@ -411,6 +411,7 @@ struct _virStorageSource {
     bool ssh_host_key_check_disabled;
     char *ssh_known_hosts_file;
     char *ssh_keyfile;
+    char *ssh_agent;
 
     /* 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 0393850ddc..a417146426 100644
--- a/src/qemu/qemu_nbdkit.c
+++ b/src/qemu/qemu_nbdkit.c
@@ -1043,6 +1043,9 @@ qemuNbdkitProcessBuildCommandSSH(qemuNbdkitProcess *proc,
             virCommandAddArgPair(cmd, "user", proc->source->ssh_user);
     }
 
+    if (proc->source->ssh_agent)
+        virCommandAddEnvPair(cmd, "SSH_AUTH_SOCK", proc->source->ssh_agent);
+
     if (proc->source->ssh_host_key_check_disabled)
         virCommandAddArgPair(cmd, "verify-remote-host", "false");
 
@@ -1165,6 +1168,10 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc,
         qemuSecurityDomainSetPathLabel(driver, vm, proc->source->ssh_keyfile, false) < 0)
         goto error;
 
+    if (proc->source->ssh_agent &&
+        qemuSecurityDomainSetPathLabel(driver, vm, proc->source->ssh_agent, false) < 0)
+        goto error;
+
     if (proc->source->ssh_known_hosts_file &&
         qemuSecurityDomainSetPathLabel(driver, vm, proc->source->ssh_known_hosts_file, false) < 0)
         goto error;
@@ -1253,6 +1260,9 @@ qemuNbdkitProcessStop(qemuNbdkitProcess *proc,
     if (proc->source->ssh_keyfile)
         qemuSecurityDomainRestorePathLabel(driver, vm, proc->source->ssh_keyfile);
 
+    if (proc->source->ssh_agent)
+        qemuSecurityDomainRestorePathLabel(driver, vm, proc->source->ssh_agent);
+
     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
index 0b52bfe0fb..f627700490 100644
--- a/tests/qemunbdkitdata/disk-network-ssh-key.args.disk0
+++ b/tests/qemunbdkitdata/disk-network-ssh-key.args.disk0
@@ -1,9 +1,9 @@
+SSH_AUTH_SOCK=/path/to/agent/socket \
 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 \
+path=test1.img \
 user=myuser \
-known-hosts=/path/to/ssh_known_hosts
+known-hosts=/path/to/ssh_known_hosts1
diff --git a/tests/qemunbdkitdata/disk-network-ssh-key.args.disk1 b/tests/qemunbdkitdata/disk-network-ssh-key.args.disk1
new file mode 100644
index 0000000000..80df9c30c6
--- /dev/null
+++ b/tests/qemunbdkitdata/disk-network-ssh-key.args.disk1
@@ -0,0 +1,9 @@
+nbdkit \
+--unix /tmp/statedir-1/nbdkit-test-disk-1.socket \
+--foreground ssh \
+host=example.org \
+port=2222 \
+path=test2.img \
+identity=/path/to/id_rsa \
+user=myuser2 \
+known-hosts=/path/to/ssh_known_hosts2
diff --git a/tests/qemuxml2argvdata/disk-network-ssh-key.xml b/tests/qemuxml2argvdata/disk-network-ssh-key.xml
index 81b92231fa..fda01e7e68 100644
--- a/tests/qemuxml2argvdata/disk-network-ssh-key.xml
+++ b/tests/qemuxml2argvdata/disk-network-ssh-key.xml
@@ -15,12 +15,23 @@
   <devices>
     <disk type='network' device='disk'>
       <driver name='qemu' type='raw'/>
-      <source protocol='ssh' name='test.img'>
+      <source protocol='ssh' name='test1.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"/>
+        <identity username='myuser' agentsock='/path/to/agent/socket'/>
+        <knownHosts path="/path/to/ssh_known_hosts1"/>
+      </source>
+      <target dev='vda' bus='virtio'/>
+    </disk>
+    <disk type='network' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source protocol='ssh' name='test2.img'>
+        <host name='example.org' port='2222'/>
+        <timeout seconds='1234'/>
+        <readahead size='1024'/>
+        <identity username='myuser2' keyfile='/path/to/id_rsa'/>
+        <knownHosts path="/path/to/ssh_known_hosts2"/>
       </source>
       <target dev='vda' bus='virtio'/>
     </disk>
-- 
2.41.0




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux