|  | .. _network_005ftls: | 
|  |  | 
|  | TLS setup for network services | 
|  | ------------------------------ | 
|  |  | 
|  | Almost all network services in QEMU have the ability to use TLS for | 
|  | session data encryption, along with x509 certificates for simple client | 
|  | authentication. What follows is a description of how to generate | 
|  | certificates suitable for usage with QEMU, and applies to the VNC | 
|  | server, character devices with the TCP backend, NBD server and client, | 
|  | and migration server and client. | 
|  |  | 
|  | At a high level, QEMU requires certificates and private keys to be | 
|  | provided in PEM format. Aside from the core fields, the certificates | 
|  | should include various extension data sets, including v3 basic | 
|  | constraints data, key purpose, key usage and subject alt name. | 
|  |  | 
|  | The GnuTLS package includes a command called ``certtool`` which can be | 
|  | used to easily generate certificates and keys in the required format | 
|  | with expected data present. Alternatively a certificate management | 
|  | service may be used. | 
|  |  | 
|  | At a minimum it is necessary to setup a certificate authority, and issue | 
|  | certificates to each server. If using x509 certificates for | 
|  | authentication, then each client will also need to be issued a | 
|  | certificate. | 
|  |  | 
|  | Assuming that the QEMU network services will only ever be exposed to | 
|  | clients on a private intranet, there is no need to use a commercial | 
|  | certificate authority to create certificates. A self-signed CA is | 
|  | sufficient, and in fact likely to be more secure since it removes the | 
|  | ability of malicious 3rd parties to trick the CA into mis-issuing certs | 
|  | for impersonating your services. The only likely exception where a | 
|  | commercial CA might be desirable is if enabling the VNC websockets | 
|  | server and exposing it directly to remote browser clients. In such a | 
|  | case it might be useful to use a commercial CA to avoid needing to | 
|  | install custom CA certs in the web browsers. | 
|  |  | 
|  | The recommendation is for the server to keep its certificates in either | 
|  | ``/etc/pki/qemu`` or for unprivileged users in ``$HOME/.pki/qemu``. | 
|  |  | 
|  | .. _tls_005fgenerate_005fca: | 
|  |  | 
|  | Setup the Certificate Authority | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | This step only needs to be performed once per organization / | 
|  | organizational unit. First the CA needs a private key. This key must be | 
|  | kept VERY secret and secure. If this key is compromised the entire trust | 
|  | chain of the certificates issued with it is lost. | 
|  |  | 
|  | :: | 
|  |  | 
|  | # certtool --generate-privkey > ca-key.pem | 
|  |  | 
|  | To generate a self-signed certificate requires one core piece of | 
|  | information, the name of the organization. A template file ``ca.info`` | 
|  | should be populated with the desired data to avoid having to deal with | 
|  | interactive prompts from certtool:: | 
|  |  | 
|  | # cat > ca.info <<EOF | 
|  | cn = Name of your organization | 
|  | ca | 
|  | cert_signing_key | 
|  | EOF | 
|  | # certtool --generate-self-signed \ | 
|  | --load-privkey ca-key.pem \ | 
|  | --template ca.info \ | 
|  | --outfile ca-cert.pem | 
|  |  | 
|  | The ``ca`` keyword in the template sets the v3 basic constraints | 
|  | extension to indicate this certificate is for a CA, while | 
|  | ``cert_signing_key`` sets the key usage extension to indicate this will | 
|  | be used for signing other keys. The generated ``ca-cert.pem`` file | 
|  | should be copied to all servers and clients wishing to utilize TLS | 
|  | support in the VNC server. The ``ca-key.pem`` must not be | 
|  | disclosed/copied anywhere except the host responsible for issuing | 
|  | certificates. | 
|  |  | 
|  | .. _tls_005fgenerate_005fserver: | 
|  |  | 
|  | Issuing server certificates | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | Each server (or host) needs to be issued with a key and certificate. | 
|  | When connecting the certificate is sent to the client which validates it | 
|  | against the CA certificate. The core pieces of information for a server | 
|  | certificate are the hostnames and/or IP addresses that will be used by | 
|  | clients when connecting. The hostname / IP address that the client | 
|  | specifies when connecting will be validated against the hostname(s) and | 
|  | IP address(es) recorded in the server certificate, and if no match is | 
|  | found the client will close the connection. | 
|  |  | 
|  | Thus it is recommended that the server certificate include both the | 
|  | fully qualified and unqualified hostnames. If the server will have | 
|  | permanently assigned IP address(es), and clients are likely to use them | 
|  | when connecting, they may also be included in the certificate. Both IPv4 | 
|  | and IPv6 addresses are supported. Historically certificates only | 
|  | included 1 hostname in the ``CN`` field, however, usage of this field | 
|  | for validation is now deprecated. Instead modern TLS clients will | 
|  | validate against the Subject Alt Name extension data, which allows for | 
|  | multiple entries. In the future usage of the ``CN`` field may be | 
|  | discontinued entirely, so providing SAN extension data is strongly | 
|  | recommended. | 
|  |  | 
|  | On the host holding the CA, create template files containing the | 
|  | information for each server, and use it to issue server certificates. | 
|  |  | 
|  | :: | 
|  |  | 
|  | # cat > server-hostNNN.info <<EOF | 
|  | organization = Name  of your organization | 
|  | cn = hostNNN.foo.example.com | 
|  | dns_name = hostNNN | 
|  | dns_name = hostNNN.foo.example.com | 
|  | ip_address = 10.0.1.87 | 
|  | ip_address = 192.8.0.92 | 
|  | ip_address = 2620:0:cafe::87 | 
|  | ip_address = 2001:24::92 | 
|  | tls_www_server | 
|  | encryption_key | 
|  | signing_key | 
|  | EOF | 
|  | # certtool --generate-privkey > server-hostNNN-key.pem | 
|  | # certtool --generate-certificate \ | 
|  | --load-ca-certificate ca-cert.pem \ | 
|  | --load-ca-privkey ca-key.pem \ | 
|  | --load-privkey server-hostNNN-key.pem \ | 
|  | --template server-hostNNN.info \ | 
|  | --outfile server-hostNNN-cert.pem | 
|  |  | 
|  | The ``dns_name`` and ``ip_address`` fields in the template are setting | 
|  | the subject alt name extension data. The ``tls_www_server`` keyword is | 
|  | the key purpose extension to indicate this certificate is intended for | 
|  | usage in a web server. Although QEMU network services are not in fact | 
|  | HTTP servers (except for VNC websockets), setting this key purpose is | 
|  | still recommended. The ``encryption_key`` and ``signing_key`` keyword is | 
|  | the key usage extension to indicate this certificate is intended for | 
|  | usage in the data session. | 
|  |  | 
|  | The ``server-hostNNN-key.pem`` and ``server-hostNNN-cert.pem`` files | 
|  | should now be securely copied to the server for which they were | 
|  | generated, and renamed to ``server-key.pem`` and ``server-cert.pem`` | 
|  | when added to the ``/etc/pki/qemu`` directory on the target host. The | 
|  | ``server-key.pem`` file is security sensitive and should be kept | 
|  | protected with file mode 0600 to prevent disclosure. | 
|  |  | 
|  | .. _tls_005fgenerate_005fclient: | 
|  |  | 
|  | Issuing client certificates | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | The QEMU x509 TLS credential setup defaults to enabling client | 
|  | verification using certificates, providing a simple authentication | 
|  | mechanism. If this default is used, each client also needs to be issued | 
|  | a certificate. The client certificate contains enough metadata to | 
|  | uniquely identify the client with the scope of the certificate | 
|  | authority. The client certificate would typically include fields for | 
|  | organization, state, city, building, etc. | 
|  |  | 
|  | Once again on the host holding the CA, create template files containing | 
|  | the information for each client, and use it to issue client | 
|  | certificates. | 
|  |  | 
|  | :: | 
|  |  | 
|  | # cat > client-hostNNN.info <<EOF | 
|  | country = GB | 
|  | state = London | 
|  | locality = City Of London | 
|  | organization = Name of your organization | 
|  | cn = hostNNN.foo.example.com | 
|  | tls_www_client | 
|  | encryption_key | 
|  | signing_key | 
|  | EOF | 
|  | # certtool --generate-privkey > client-hostNNN-key.pem | 
|  | # certtool --generate-certificate \ | 
|  | --load-ca-certificate ca-cert.pem \ | 
|  | --load-ca-privkey ca-key.pem \ | 
|  | --load-privkey client-hostNNN-key.pem \ | 
|  | --template client-hostNNN.info \ | 
|  | --outfile client-hostNNN-cert.pem | 
|  |  | 
|  | The subject alt name extension data is not required for clients, so | 
|  | the ``dns_name`` and ``ip_address`` fields are not included. The | 
|  | ``tls_www_client`` keyword is the key purpose extension to indicate this | 
|  | certificate is intended for usage in a web client. Although QEMU network | 
|  | clients are not in fact HTTP clients, setting this key purpose is still | 
|  | recommended. The ``encryption_key`` and ``signing_key`` keyword is the | 
|  | key usage extension to indicate this certificate is intended for usage | 
|  | in the data session. | 
|  |  | 
|  | The ``client-hostNNN-key.pem`` and ``client-hostNNN-cert.pem`` files | 
|  | should now be securely copied to the client for which they were | 
|  | generated, and renamed to ``client-key.pem`` and ``client-cert.pem`` | 
|  | when added to the ``/etc/pki/qemu`` directory on the target host. The | 
|  | ``client-key.pem`` file is security sensitive and should be kept | 
|  | protected with file mode 0600 to prevent disclosure. | 
|  |  | 
|  | If a single host is going to be using TLS in both a client and server | 
|  | role, it is possible to create a single certificate to cover both roles. | 
|  | This would be quite common for the migration and NBD services, where a | 
|  | QEMU process will be started by accepting a TLS protected incoming | 
|  | migration, and later itself be migrated out to another host. To generate | 
|  | a single certificate, simply include the template data from both the | 
|  | client and server instructions in one. | 
|  |  | 
|  | :: | 
|  |  | 
|  | # cat > both-hostNNN.info <<EOF | 
|  | country = GB | 
|  | state = London | 
|  | locality = City Of London | 
|  | organization = Name of your organization | 
|  | cn = hostNNN.foo.example.com | 
|  | dns_name = hostNNN | 
|  | dns_name = hostNNN.foo.example.com | 
|  | ip_address = 10.0.1.87 | 
|  | ip_address = 192.8.0.92 | 
|  | ip_address = 2620:0:cafe::87 | 
|  | ip_address = 2001:24::92 | 
|  | tls_www_server | 
|  | tls_www_client | 
|  | encryption_key | 
|  | signing_key | 
|  | EOF | 
|  | # certtool --generate-privkey > both-hostNNN-key.pem | 
|  | # certtool --generate-certificate \ | 
|  | --load-ca-certificate ca-cert.pem \ | 
|  | --load-ca-privkey ca-key.pem \ | 
|  | --load-privkey both-hostNNN-key.pem \ | 
|  | --template both-hostNNN.info \ | 
|  | --outfile both-hostNNN-cert.pem | 
|  |  | 
|  | When copying the PEM files to the target host, save them twice, once as | 
|  | ``server-cert.pem`` and ``server-key.pem``, and again as | 
|  | ``client-cert.pem`` and ``client-key.pem``. | 
|  |  | 
|  | .. _tls_005fcreds_005fsetup: | 
|  |  | 
|  | TLS x509 credential configuration | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | QEMU has a standard mechanism for loading x509 credentials that will be | 
|  | used for network services and clients. It requires specifying the | 
|  | ``tls-creds-x509`` class name to the ``--object`` command line argument | 
|  | for the system emulators. Each set of credentials loaded should be given | 
|  | a unique string identifier via the ``id`` parameter. A single set of TLS | 
|  | credentials can be used for multiple network backends, so VNC, | 
|  | migration, NBD, character devices can all share the same credentials. | 
|  | Note, however, that credentials for use in a client endpoint must be | 
|  | loaded separately from those used in a server endpoint. | 
|  |  | 
|  | When specifying the object, the ``dir`` parameters specifies which | 
|  | directory contains the credential files. This directory is expected to | 
|  | contain files with the names mentioned previously, ``ca-cert.pem``, | 
|  | ``server-key.pem``, ``server-cert.pem``, ``client-key.pem`` and | 
|  | ``client-cert.pem`` as appropriate. It is also possible to include a set | 
|  | of pre-generated Diffie-Hellman (DH) parameters in a file | 
|  | ``dh-params.pem``, which can be created using the | 
|  | ``certtool --generate-dh-params`` command. If omitted, QEMU will | 
|  | dynamically generate DH parameters when loading the credentials. | 
|  |  | 
|  | The ``endpoint`` parameter indicates whether the credentials will be | 
|  | used for a network client or server, and determines which PEM files are | 
|  | loaded. | 
|  |  | 
|  | The ``verify`` parameter determines whether x509 certificate validation | 
|  | should be performed. This defaults to enabled, meaning clients will | 
|  | always validate the server hostname against the certificate subject alt | 
|  | name fields and/or CN field. It also means that servers will request | 
|  | that clients provide a certificate and validate them. Verification | 
|  | should never be turned off for client endpoints, however, it may be | 
|  | turned off for server endpoints if an alternative mechanism is used to | 
|  | authenticate clients. For example, the VNC server can use SASL to | 
|  | authenticate clients instead. | 
|  |  | 
|  | To load server credentials with client certificate validation enabled | 
|  |  | 
|  | .. parsed-literal:: | 
|  |  | 
|  | |qemu_system| -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server | 
|  |  | 
|  | while to load client credentials use | 
|  |  | 
|  | .. parsed-literal:: | 
|  |  | 
|  | |qemu_system| -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client | 
|  |  | 
|  | Network services which support TLS will all have a ``tls-creds`` | 
|  | parameter which expects the ID of the TLS credentials object. For | 
|  | example with VNC: | 
|  |  | 
|  | .. parsed-literal:: | 
|  |  | 
|  | |qemu_system| -vnc 0.0.0.0:0,tls-creds=tls0 | 
|  |  | 
|  | .. _tls_005fpsk: | 
|  |  | 
|  | TLS Pre-Shared Keys (PSK) | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | Instead of using certificates, you may also use TLS Pre-Shared Keys | 
|  | (TLS-PSK). This can be simpler to set up than certificates but is less | 
|  | scalable. | 
|  |  | 
|  | Use the GnuTLS ``psktool`` program to generate a ``keys.psk`` file | 
|  | containing one or more usernames and random keys:: | 
|  |  | 
|  | mkdir -m 0700 /tmp/keys | 
|  | psktool -u rich -p /tmp/keys/keys.psk | 
|  |  | 
|  | TLS-enabled servers such as ``qemu-nbd`` can use this directory like so:: | 
|  |  | 
|  | qemu-nbd \ | 
|  | -t -x / \ | 
|  | --object tls-creds-psk,id=tls0,endpoint=server,dir=/tmp/keys \ | 
|  | --tls-creds tls0 \ | 
|  | image.qcow2 | 
|  |  | 
|  | When connecting from a qemu-based client you must specify the directory | 
|  | containing ``keys.psk`` and an optional username (defaults to "qemu"):: | 
|  |  | 
|  | qemu-img info \ | 
|  | --object tls-creds-psk,id=tls0,dir=/tmp/keys,username=rich,endpoint=client \ | 
|  | --image-opts \ | 
|  | file.driver=nbd,file.host=localhost,file.port=10809,file.tls-creds=tls0,file.export=/ |