In common with VNC, the QEMU driver configuration file is used specify the host level TLS certificate location and a default password / listen address * src/qemu/qemu.conf: Add spice_listen, spice_tls, spice_tls_x509_cert_dir & spice_password config params * src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Parsing of spice config parameters and updating -spice arg generation to use them * tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args, tests/qemuxml2argvtest.c: Expand test case to cover driver level configuration --- src/qemu/qemu.conf | 40 +++++++++++++ src/qemu/qemu_conf.c | 62 +++++++++++++++++++- src/qemu/qemu_conf.h | 4 + src/qemu/qemu_driver.c | 15 ++++- .../qemuxml2argv-graphics-spice-rhel6.args | 2 +- tests/qemuxml2argvtest.c | 7 ++- 6 files changed, 124 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 3da332f..980dc8b 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -80,6 +80,46 @@ +# SPICE is configured to listen on 127.0.0.1 by default. +# To make it listen on all public interfaces, uncomment +# this next option. +# +# NB, strong recommendation to enable TLS + x509 certificate +# verification when allowing public access +# +# spice_listen = "0.0.0.0" + + +# Enable use of TLS encryption on the SPICE server. +# +# It is necessary to setup CA and issue a server certificate +# before enabling this. +# +# spice_tls = 1 + + +# Use of TLS requires that x509 certificates be issued. The +# default it to keep them in /etc/pki/libvirt-spice. This directory +# must contain +# +# ca-cert.pem - the CA master certificate +# server-cert.pem - the server certificate signed with ca-cert.pem +# server-key.pem - the server private key +# +# This option allows the certificate directory to be changed +# +# spice_tls_x509_cert_dir = "/etc/pki/libvirt-spice" + + +# The default SPICE password. This parameter is only used if the +# per-domain XML config does not already provide a password. To +# allow access without passwords, leave this commented out. An +# empty string will still enable passwords, but be rejected by +# QEMU effectively preventing any use of SPICE. Obviously change +# this example here before you set this +# +# spice_password = "XYZ12345" + # The default security driver is SELinux. If SELinux is disabled # on the host, then the security driver will automatically disable diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index e4a5985..ca251a3 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -115,6 +115,15 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, return -1; } + if (!(driver->spiceListen = strdup("127.0.0.1"))) { + virReportOOMError(); + return -1; + } + if (!(driver->spiceTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-spice"))) { + virReportOOMError(); + return -1; + } + #ifdef HAVE_MNTENT_H /* For privileged driver, try and find hugepage mount automatically. * Non-privileged driver requires admin to create a dir for the @@ -213,6 +222,43 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, } } + p = virConfGetValue (conf, "spice_tls"); + CHECK_TYPE ("spice_tls", VIR_CONF_LONG); + if (p) driver->spiceTLS = p->l; + + p = virConfGetValue (conf, "spice_tls_x509_cert_dir"); + CHECK_TYPE ("spice_tls_x509_cert_dir", VIR_CONF_STRING); + if (p && p->str) { + VIR_FREE(driver->spiceTLSx509certdir); + if (!(driver->spiceTLSx509certdir = strdup(p->str))) { + virReportOOMError(); + virConfFree(conf); + return -1; + } + } + + p = virConfGetValue (conf, "spice_listen"); + CHECK_TYPE ("spice_listen", VIR_CONF_STRING); + if (p && p->str) { + VIR_FREE(driver->spiceListen); + if (!(driver->spiceListen = strdup(p->str))) { + virReportOOMError(); + virConfFree(conf); + return -1; + } + } + + p = virConfGetValue (conf, "spice_password"); + CHECK_TYPE ("spice_password", VIR_CONF_STRING); + if (p && p->str) { + VIR_FREE(driver->spicePassword); + if (!(driver->spicePassword = strdup(p->str))) { + virReportOOMError(); + virConfFree(conf); + return -1; + } + } + p = virConfGetValue (conf, "user"); CHECK_TYPE ("user", VIR_CONF_STRING); if (!(user = strdup(p && p->str ? p->str : QEMU_USER))) { @@ -4424,11 +4470,25 @@ int qemudBuildCommandLine(virConnectPtr conn, virBufferVSprintf(&opt, "port=%u", def->graphics[0]->data.spice.port); - if (def->graphics[0]->data.spice.tlsPort) + if (driver->spiceTLS && def->graphics[0]->data.spice.tlsPort != -1) virBufferVSprintf(&opt, ",tls-port=%u", def->graphics[0]->data.spice.tlsPort); if (def->graphics[0]->data.spice.listenAddr) virBufferVSprintf(&opt, ",addr=%s", def->graphics[0]->data.spice.listenAddr); + else if (driver->spiceListen) + virBufferVSprintf(&opt, ",addr=%s", driver->spiceListen); + + /* In the password case we set it via monitor command, to avoid + * making it visible on CLI, so there's no use of password=XXX + * in this bit of the code */ + if (!def->graphics[0]->data.spice.passwd && + !driver->spicePassword) + virBufferAddLit(&opt, ",disable-ticketing"); + + if (driver->spiceTLS) + virBufferVSprintf(&opt, ",x509-dir=%s", + driver->spiceTLSx509certdir); + if (virBufferError(&opt)) goto no_memory; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 2d169bd..bf18102 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -131,6 +131,10 @@ struct qemud_driver { char *vncListen; char *vncPassword; char *vncSASLdir; + unsigned int spiceTLS : 1; + char *spiceTLSx509certdir; + char *spiceListen; + char *spicePassword; char *hugetlbfs_mount; char *hugepage_path; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2aa39c1..f290172 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3213,13 +3213,22 @@ static int qemudStartVMDaemon(virConnectPtr conn, } else if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE && vm->def->graphics[0]->data.spice.autoport) { int port = qemudNextFreePort(5900); - int tlsPort = port == -1 ? -1 : qemudNextFreePort(port + 1); - if (port < 0 || tlsPort < 0) { + int tlsPort = -1; + if (port < 0) { qemuReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Unable to find an unused SPICE ports")); + "%s", _("Unable to find an unused SPICE port")); goto cleanup; } + if (driver->spiceTLS) { + tlsPort = qemudNextFreePort(port + 1); + if (tlsPort < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Unable to find an unused SPICE TLS port")); + goto cleanup; + } + } + vm->def->graphics[0]->data.spice.port = port; vm->def->graphics[0]->data.spice.tlsPort = tlsPort; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args index 8d195e5..e412fdb 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-rhel6.args @@ -1 +1 @@ -LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=spice /usr/bin/qemu -S -M pc -m 214 -smp 1 -nodefaults -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -usb -spice port=5903,tls-port=5904,addr=127.0.0.1 -vga qxl -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=spice /usr/bin/qemu -S -M pc -m 214 -smp 1 -nodefaults -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -usb -spice port=5903,tls-port=5904,addr=127.0.0.1,x509-dir=/etc/pki/libvirt-spice -vga qxl -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 5e46dca..10bf4b1 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -198,8 +198,13 @@ mymain(int argc, char **argv) return EXIT_FAILURE; if ((driver.hugepage_path = strdup("/dev/hugepages/libvirt/qemu")) == NULL) return EXIT_FAILURE; + driver.spiceTLS = 1; + if (!(driver.spiceTLSx509certdir = strdup("/etc/pki/libvirt-spice"))) + return EXIT_FAILURE; + if (!(driver.spicePassword = strdup("123456"))) + return EXIT_FAILURE; -# define DO_TEST_FULL(name, extraFlags, migrateFrom) \ +# define DO_TEST_FULL(name, extraFlags, migrateFrom) \ do { \ const struct testInfo info = { name, extraFlags, migrateFrom }; \ if (virtTestRun("QEMU XML-2-ARGV " name, \ -- 1.6.6.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list