| @node network_tls |
| @section 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 @code{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 |
| @code{/etc/pki/qemu} or for unprivileged users in @code{$HOME/.pki/qemu}. |
| |
| @menu |
| * tls_generate_ca:: |
| * tls_generate_server:: |
| * tls_generate_client:: |
| * tls_creds_setup:: |
| * tls_psk:: |
| @end menu |
| @node tls_generate_ca |
| @subsection 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. |
| |
| @example |
| # certtool --generate-privkey > ca-key.pem |
| @end example |
| |
| To generate a self-signed certificate requires one core piece of information, |
| the name of the organization. A template file @code{ca.info} should be |
| populated with the desired data to avoid having to deal with interactive |
| prompts from certtool: |
| @example |
| # 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 |
| @end example |
| |
| The @code{ca} keyword in the template sets the v3 basic constraints extension |
| to indicate this certificate is for a CA, while @code{cert_signing_key} sets |
| the key usage extension to indicate this will be used for signing other keys. |
| The generated @code{ca-cert.pem} file should be copied to all servers and |
| clients wishing to utilize TLS support in the VNC server. The @code{ca-key.pem} |
| must not be disclosed/copied anywhere except the host responsible for issuing |
| certificates. |
| |
| @node tls_generate_server |
| @subsection 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 @code{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 @code{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. |
| |
| @example |
| # 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 |
| @end example |
| |
| The @code{dns_name} and @code{ip_address} fields in the template are setting |
| the subject alt name extension data. The @code{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 @code{encryption_key} and @code{signing_key} keyword is the key usage |
| extension to indicate this certificate is intended for usage in the data |
| session. |
| |
| The @code{server-hostNNN-key.pem} and @code{server-hostNNN-cert.pem} files |
| should now be securely copied to the server for which they were generated, |
| and renamed to @code{server-key.pem} and @code{server-cert.pem} when added |
| to the @code{/etc/pki/qemu} directory on the target host. The @code{server-key.pem} |
| file is security sensitive and should be kept protected with file mode 0600 |
| to prevent disclosure. |
| |
| @node tls_generate_client |
| @subsection 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. |
| |
| |
| @example |
| # 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 |
| @end example |
| |
| The subject alt name extension data is not required for clients, so the |
| the @code{dns_name} and @code{ip_address} fields are not included. |
| The @code{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 @code{encryption_key} and @code{signing_key} keyword |
| is the key usage extension to indicate this certificate is intended for |
| usage in the data session. |
| |
| The @code{client-hostNNN-key.pem} and @code{client-hostNNN-cert.pem} files |
| should now be securely copied to the client for which they were generated, |
| and renamed to @code{client-key.pem} and @code{client-cert.pem} when added |
| to the @code{/etc/pki/qemu} directory on the target host. The @code{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. |
| |
| @example |
| # 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 |
| @end example |
| |
| When copying the PEM files to the target host, save them twice, |
| once as @code{server-cert.pem} and @code{server-key.pem}, and |
| again as @code{client-cert.pem} and @code{client-key.pem}. |
| |
| @node tls_creds_setup |
| @subsection 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 |
| @code{tls-creds-x509} class name to the @code{--object} command line |
| argument for the system emulators. Each set of credentials loaded should |
| be given a unique string identifier via the @code{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 @code{dir} parameters specifies which |
| directory contains the credential files. This directory is expected to |
| contain files with the names mentioned previously, @code{ca-cert.pem}, |
| @code{server-key.pem}, @code{server-cert.pem}, @code{client-key.pem} |
| and @code{client-cert.pem} as appropriate. It is also possible to |
| include a set of pre-generated Diffie-Hellman (DH) parameters in a file |
| @code{dh-params.pem}, which can be created using the |
| @code{certtool --generate-dh-params} command. If omitted, QEMU will |
| dynamically generate DH parameters when loading the credentials. |
| |
| The @code{endpoint} parameter indicates whether the credentials will |
| be used for a network client or server, and determines which PEM |
| files are loaded. |
| |
| The @code{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 |
| |
| @example |
| @value{qemu_system} -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server |
| @end example |
| |
| while to load client credentials use |
| |
| @example |
| @value{qemu_system} -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client |
| @end example |
| |
| Network services which support TLS will all have a @code{tls-creds} |
| parameter which expects the ID of the TLS credentials object. For |
| example with VNC: |
| |
| @example |
| @value{qemu_system} -vnc 0.0.0.0:0,tls-creds=tls0 |
| @end example |
| |
| @node tls_psk |
| @subsection 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 @code{psktool} program to generate a @code{keys.psk} |
| file containing one or more usernames and random keys: |
| |
| @example |
| mkdir -m 0700 /tmp/keys |
| psktool -u rich -p /tmp/keys/keys.psk |
| @end example |
| |
| TLS-enabled servers such as qemu-nbd can use this directory like so: |
| |
| @example |
| qemu-nbd \ |
| -t -x / \ |
| --object tls-creds-psk,id=tls0,endpoint=server,dir=/tmp/keys \ |
| --tls-creds tls0 \ |
| image.qcow2 |
| @end example |
| |
| When connecting from a qemu-based client you must specify the |
| directory containing @code{keys.psk} and an optional @var{username} |
| (defaults to ``qemu''): |
| |
| @example |
| 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=/ |
| @end example |
| |