123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- .. _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=/
|