9. TLS

TLS support allows to encrypt all/some of the channels Spice uses for its communication. A separate port is used for the encrypted channels. When connecting through a TLS channel, the Spice client will verify the certificate sent by the host. It will check that this certificate matches the hostname it’s connecting, and that this certificate is signed by a known certificate authority (CA). This can be achieved by either getting the host certificate signed by an official CA, or by passing to the client the certificate of the authority which signed the host certificate. The latter allows the use of self-signed certificates.

9.1. Configuration

Important

It’s not currently possible to define the CA certificate/host certificate to use for the TLS connection using virt-manager, see the next section for how to enable this using libvirt.

Using libvirt. The certificate must be specified in libvirtd configuration file in /etc/libvirt/qemu.conf (or in ~/.config/libvirt/qemu.conf if you are using a session libvirt). See the documentation in this file reproduced below:

# 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"

Once the above is done, when the domain is running, you should get something like what is below if you are leaving Spice port allocation up to libvirt:

host$ virsh domdisplay
spice://127.0.0.1?tls-port=5901
host$

This means that the connection is possible both through TLS and without any encryption. You can edit the libvirt graphics node if you want to change that behaviour and only allow connections through TLS:

<graphics type='spice' autoport='yes' defaultMode='secure'/>

Using QEMU. QEMU expects the certificates to be named the same way as what libvirt expects in the previous paragraph. The directory where these certificates can be found is specified as options to the -spice command line parameters:

-spice port=5900,tls-port=5901,disable-ticketing,x509-dir=/etc/pki/libvirt-spice

9.2. Client

We need to change 2 things when starting the client:

  • specify the tls port to use
  • specify the CA certificate to use when verifying the host certificate

With remote-viewer, this is done this way:

client$ remote-viewer --spice-ca-file=/etc/pki/libvirt-spice/ca-cert.ca spice://myhost?tls-port=5901

9.3. Generating self-signed certificates

The following script can be used to create the various certificates needed to use a TLS Spice connection. Make sure to substitute the hostname of your Spice host in the subject of the certificate signing request.

SERVER_KEY=server-key.pem

# creating a key for our ca
if [ ! -e ca-key.pem ]; then
    openssl genrsa -des3 -out ca-key.pem 1024
fi
# creating a ca
if [ ! -e ca-cert.pem ]; then
    openssl req -new -x509 -days 1095 -key ca-key.pem -out ca-cert.pem -utf8 -subj "/C=IL/L=Raanana/O=Red Hat/CN=my CA"
fi
# create server key
if [ ! -e $SERVER_KEY ]; then
    openssl genrsa -out $SERVER_KEY 1024
fi
# create a certificate signing request (csr)
if [ ! -e server-key.csr ]; then
    openssl req -new -key $SERVER_KEY -out server-key.csr -utf8 -subj "/C=IL/L=Raanana/O=Red Hat/CN=myhostname.example.com"
fi
# signing our server certificate with this ca
if [ ! -e server-cert.pem ]; then
    openssl x509 -req -days 1095 -in server-key.csr -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
fi

# now create a key that doesn't require a passphrase
openssl rsa -in $SERVER_KEY -out $SERVER_KEY.insecure
mv $SERVER_KEY $SERVER_KEY.secure
mv $SERVER_KEY.insecure $SERVER_KEY

# show the results (no other effect)
openssl rsa -noout -text -in $SERVER_KEY
openssl rsa -noout -text -in ca-key.pem
openssl req -noout -text -in server-key.csr
openssl x509 -noout -text -in server-cert.pem
openssl x509 -noout -text -in ca-cert.pem