mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
docs: convert 'tlscerts' page to rst
Note that links from the first table leading to sections of this document further below were removed for simplicity. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
parent
d2978caea7
commit
04deb69bd3
@ -31,7 +31,6 @@ docs_html_in_files = [
|
||||
'internals',
|
||||
'remote',
|
||||
'storage',
|
||||
'tlscerts',
|
||||
'uri',
|
||||
'windows',
|
||||
]
|
||||
@ -110,6 +109,7 @@ docs_rst_files = [
|
||||
'testapi',
|
||||
'testsuites',
|
||||
'testtck',
|
||||
'tlscerts',
|
||||
]
|
||||
|
||||
# list of web targets to build for docs/web rule
|
||||
|
@ -1,413 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<h1>TLS x509 certificate setup</h1>
|
||||
|
||||
<ul id="toc"></ul>
|
||||
|
||||
<h2>
|
||||
<a id="Remote_PKI">Public Key Infrastructure set up</a>
|
||||
</h2>
|
||||
<p>
|
||||
If you are unsure how to create TLS certificates, skip to the
|
||||
next section.
|
||||
</p>
|
||||
<table class="top_table">
|
||||
<tr>
|
||||
<th> Location </th>
|
||||
<th> Machine </th>
|
||||
<th> Description </th>
|
||||
<th> Required fields </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>/etc/pki/CA/cacert.pem</code>
|
||||
</td>
|
||||
<td> Installed on the client and server </td>
|
||||
<td> CA's certificate (<a href="#Remote_TLS_CA">more info</a>)</td>
|
||||
<td> n/a </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>$HOME/.pki/cacert.pem</code>
|
||||
</td>
|
||||
<td> Installed on the client </td>
|
||||
<td> CA's certificate (<a href="#Remote_TLS_CA">more info</a>)</td>
|
||||
<td> n/a </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>/etc/pki/libvirt/private/serverkey.pem</code>
|
||||
</td>
|
||||
<td> Installed on the server </td>
|
||||
<td> Server's private key (<a href="#Remote_TLS_server_certificates">more info</a>)</td>
|
||||
<td> n/a </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>/etc/pki/libvirt/servercert.pem</code>
|
||||
</td>
|
||||
<td> Installed on the server </td>
|
||||
<td> Server's certificate signed by the CA.
|
||||
(<a href="#Remote_TLS_server_certificates">more info</a>) </td>
|
||||
<td> CommonName (CN) must be the hostname of the server as it
|
||||
is seen by clients. All hostname and IP address variants that might
|
||||
be used to reach the server should be listed in Subject Alt Name
|
||||
fields.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>/etc/pki/libvirt/private/clientkey.pem</code>
|
||||
</td>
|
||||
<td> Installed on the client </td>
|
||||
<td> Client's private key. (<a href="#Remote_TLS_client_certificates">more info</a>) </td>
|
||||
<td> n/a </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>/etc/pki/libvirt/clientcert.pem</code>
|
||||
</td>
|
||||
<td> Installed on the client </td>
|
||||
<td> Client's certificate signed by the CA
|
||||
(<a href="#Remote_TLS_client_certificates">more info</a>) </td>
|
||||
<td> Distinguished Name (DN) can be checked against an access
|
||||
control list (<code>tls_allowed_dn_list</code>).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>$HOME/.pki/libvirt/clientkey.pem</code>
|
||||
</td>
|
||||
<td> Installed on the client </td>
|
||||
<td> Client's private key. (<a href="#Remote_TLS_client_certificates">more info</a>) </td>
|
||||
<td> n/a </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>$HOME/.pki/libvirt/clientcert.pem</code>
|
||||
</td>
|
||||
<td> Installed on the client </td>
|
||||
<td> Client's certificate signed by the CA
|
||||
(<a href="#Remote_TLS_client_certificates">more info</a>) </td>
|
||||
<td> Distinguished Name (DN) can be checked against an access
|
||||
control list (<code>tls_allowed_dn_list</code>).
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
If 'pkipath' is specified in URI, then all the client
|
||||
certificates must be found in the path specified, otherwise the
|
||||
connection will fail with a fatal error. If 'pkipath' is not
|
||||
specified:
|
||||
</p>
|
||||
<ul>
|
||||
<li> For a non-root user, libvirt tries to find the certificates
|
||||
in $HOME/.pki/libvirt first. If the required CA certificate cannot
|
||||
be found, then the global default location
|
||||
(/etc/pki/CA/cacert.pem) will be used.
|
||||
Likewise, if either the client certificate
|
||||
or the client key cannot be found, then the global default
|
||||
locations (/etc/pki/libvirt/clientcert.pem,
|
||||
/etc/pki/libvirt/private/clientkey.pem) will be used.
|
||||
</li>
|
||||
<li> For the root user, the global default locations will always be used.</li>
|
||||
</ul>
|
||||
<h2>
|
||||
<a id="Remote_TLS_background">Background to TLS certificates</a>
|
||||
</h2>
|
||||
<p>
|
||||
Libvirt supports TLS certificates for verifying the identity
|
||||
of the server and clients. There are two distinct checks involved:
|
||||
</p>
|
||||
<ul>
|
||||
<li> The client should know that it is connecting to the right
|
||||
server. Checking done by client by matching the certificate that
|
||||
the server sends to the server's hostname. May be disabled by adding
|
||||
<code>?no_verify=1</code> to the
|
||||
<a href="uri.html#Remote_URI_parameters">remote URI</a>.
|
||||
</li>
|
||||
<li> The server should know that only permitted clients are
|
||||
connecting. This can be done based on client's IP address, or on
|
||||
client's IP address and client's certificate. Checking done by the
|
||||
server. May be enabled and disabled in the <a href="remote.html#Remote_libvirtd_configuration">libvirtd.conf file</a>.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
For full certificate checking you will need to have certificates
|
||||
issued by a recognised <a href="https://en.wikipedia.org/wiki/Certificate_authority">Certificate
|
||||
Authority (CA)</a> for your server(s) and all clients. To avoid the
|
||||
expense of getting certificates from a commercial CA, you can set up
|
||||
your own CA and tell your server(s) and clients to trust certificates
|
||||
issues by your own CA. Follow the instructions in the next section.
|
||||
</p>
|
||||
<p>
|
||||
Be aware that the <a href="remote.html#Remote_libvirtd_configuration">default
|
||||
configuration for libvirtd</a> allows any client to connect provided
|
||||
they have a valid certificate issued by the CA for their own IP
|
||||
address. You may want to change this to make it less (or more)
|
||||
permissive, depending on your needs.
|
||||
</p>
|
||||
<h2>
|
||||
<a id="Remote_TLS_CA">Setting up a Certificate Authority (CA)</a>
|
||||
</h2>
|
||||
<p>
|
||||
You will need the <a href="https://www.gnutls.org/manual/html_node/certtool-Invocation.html">GnuTLS
|
||||
certtool program documented here</a>. In Fedora, it is in the
|
||||
<code>gnutls-utils</code> package.
|
||||
</p>
|
||||
<p>
|
||||
Create a private key for your CA:
|
||||
</p>
|
||||
<pre>
|
||||
certtool --generate-privkey > cakey.pem
|
||||
</pre>
|
||||
<p>
|
||||
and self-sign it by creating a file with the
|
||||
signature details called
|
||||
<code>ca.info</code> containing:
|
||||
</p>
|
||||
<pre>
|
||||
cn = <i>Name of your organization</i>
|
||||
ca
|
||||
cert_signing_key
|
||||
</pre>
|
||||
<pre>
|
||||
certtool --generate-self-signed --load-privkey cakey.pem \
|
||||
--template ca.info --outfile cacert.pem
|
||||
</pre>
|
||||
<p>
|
||||
(You can delete <code>ca.info</code> file now if you
|
||||
want).
|
||||
</p>
|
||||
<p>
|
||||
Now you have two files which matter:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>cakey.pem</code> - Your CA's private key (keep this very secret!)
|
||||
</li>
|
||||
<li><code>cacert.pem</code> - Your CA's certificate (this is public).
|
||||
</li>
|
||||
</ul>
|
||||
<p><code>cacert.pem</code> has to be installed on clients and
|
||||
server(s) to let them know that they can trust certificates issued by
|
||||
your CA.
|
||||
</p>
|
||||
<p>
|
||||
The normal installation directory for <code>cacert.pem</code>
|
||||
is <code>/etc/pki/CA/cacert.pem</code> on all clients and servers.
|
||||
</p>
|
||||
<p>
|
||||
To see the contents of this file, do:
|
||||
</p>
|
||||
<pre><b>certtool -i --infile cacert.pem</b>
|
||||
|
||||
X.509 certificate info:
|
||||
|
||||
Version: 3
|
||||
Serial Number (hex): 00
|
||||
Subject: CN=Libvirt Project
|
||||
Issuer: CN=Libvirt Project
|
||||
Signature Algorithm: RSA-SHA
|
||||
Validity:
|
||||
Not Before: Mon Jun 18 16:22:18 2007
|
||||
Not After: Tue Jun 17 16:22:18 2008
|
||||
<i>[etc]</i>
|
||||
</pre>
|
||||
<p>
|
||||
This is all that is required to set up your CA. Keep the CA's private
|
||||
key carefully as you will need it when you come to issue certificates
|
||||
for your clients and servers.
|
||||
</p>
|
||||
<h2>
|
||||
<a id="Remote_TLS_server_certificates">Issuing server certificates</a>
|
||||
</h2>
|
||||
<p>
|
||||
For each server (libvirtd) you need to issue a certificate
|
||||
containing one or more hostnames and/or IP addresses.
|
||||
Historically the CommonName (CN) field would contain the
|
||||
hostname of the server and would match the hostname used
|
||||
in the URI that clients pass to libvirt. In most TLS implementations
|
||||
the CN field is considered legacy data. The preferential mechanism
|
||||
is to use Subject Alt Name (SAN) extension fields to validate
|
||||
against. In the future use of the CN field for validation may be
|
||||
discontinued entirely, so it is strongly recommended to
|
||||
include the SAN fields.
|
||||
</p>
|
||||
<p>
|
||||
In the example below, clients will be connecting to the
|
||||
server using a <a href="uri.html#URI_remote">URI</a> of
|
||||
<code>qemu://compute1.libvirt.org/system</code>, so the CN
|
||||
must be "<code>compute1.libvirt.org</code>".
|
||||
</p>
|
||||
<p>
|
||||
Make a private key for the server:
|
||||
</p>
|
||||
<pre>
|
||||
certtool --generate-privkey > serverkey.pem
|
||||
</pre>
|
||||
<p>
|
||||
and sign that key with the CA's private key by first
|
||||
creating a template file called <code>server.info</code>.
|
||||
The template file will contain a number of fields to define
|
||||
the server as follows:
|
||||
</p>
|
||||
<pre>
|
||||
organization = <i>Name of your organization</i>
|
||||
cn = compute1.libvirt.org
|
||||
dns_name = compute1
|
||||
dns_name = compute1.libvirt.org
|
||||
ip_address = 10.0.0.74
|
||||
ip_address = 192.168.1.24
|
||||
ip_address = 2001:cafe::74
|
||||
ip_address = fe20::24
|
||||
tls_www_server
|
||||
encryption_key
|
||||
signing_key
|
||||
</pre>
|
||||
<p>
|
||||
The 'cn' field should refer to the fully qualified public
|
||||
hostname of the server. For the SAN extension data, there
|
||||
must also be one or more 'dns_name' fields that contain all
|
||||
possible hostnames that can be reasonably used by clients
|
||||
to reach the server, both with and without domain name
|
||||
qualifiers. If clients are likely to connect to the server
|
||||
by IP address, then one or more 'ip_address' fields should
|
||||
also be added.
|
||||
</p>
|
||||
<p>
|
||||
Use the template file as input to a <code>certtool</code>
|
||||
command to sign the server certificate:
|
||||
</p>
|
||||
<pre>
|
||||
certtool --generate-certificate --load-privkey serverkey.pem \
|
||||
--load-ca-certificate cacert.pem --load-ca-privkey cakey.pem \
|
||||
--template server.info --outfile servercert.pem
|
||||
</pre>
|
||||
<p>
|
||||
This gives two files:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>serverkey.pem</code> - The server's private key.
|
||||
</li>
|
||||
<li><code>servercert.pem</code> - The server's public key.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
We can examine this certificate and its signature:
|
||||
</p>
|
||||
<pre><b>certtool -i --infile servercert.pem</b>
|
||||
X.509 certificate info:
|
||||
|
||||
Version: 3
|
||||
Serial Number (hex): 00
|
||||
Subject: O=Libvirt Project,CN=compute1.libvirt.org
|
||||
Issuer: CN=Libvirt Project
|
||||
Signature Algorithm: RSA-SHA
|
||||
Validity:
|
||||
Not Before: Wed Oct 04 09:09:44 UTC 2017
|
||||
Not After: Thu Oct 04 09:09:44 UTC 2018
|
||||
Extensions:
|
||||
Basic Constraints (critical):
|
||||
Certificate Authority (CA): FALSE
|
||||
Subject Alternative Name (not critical):
|
||||
DNSname: compute1
|
||||
DNSname: compute1.libvirt.org
|
||||
IPAddress: 10.0.0.74
|
||||
IPAddress: 192.168.1.24
|
||||
IPAddress: 2001:cafe::74
|
||||
IPAddress: fe20::24
|
||||
</pre>
|
||||
<p>
|
||||
Note the "Issuer" CN is "Libvirt Project" (the CA) and
|
||||
the "Subject" CN is "compute1.libvirt.org" (the server).
|
||||
Notice that the hostname listed in the CN must also
|
||||
be duplicated as a DNSname entry
|
||||
</p>
|
||||
<p>
|
||||
Finally we have two files to install:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>serverkey.pem</code> is
|
||||
the server's private key which should be copied to the
|
||||
server <i>only</i> as
|
||||
<code>/etc/pki/libvirt/private/serverkey.pem</code>.
|
||||
</li>
|
||||
<li><code>servercert.pem</code> is the server's certificate
|
||||
which can be installed on the server as
|
||||
<code>/etc/pki/libvirt/servercert.pem</code>.
|
||||
</li>
|
||||
</ul>
|
||||
<h2>
|
||||
<a id="Remote_TLS_client_certificates">Issuing client certificates</a>
|
||||
</h2>
|
||||
<p>
|
||||
For each client (ie. any program linked with libvirt, such as
|
||||
<a href="https://virt-manager.org/">virt-manager</a>)
|
||||
you need to issue a certificate with the X.509 Distinguished Name (DN)
|
||||
set to a suitable name. You can decide this on a company / organisation
|
||||
policy. For example:
|
||||
</p>
|
||||
<pre>
|
||||
C=GB,ST=London,L=London,O=Libvirt Project,CN=<i>name_of_client</i>
|
||||
</pre>
|
||||
<p>
|
||||
The process is the same as for
|
||||
<a href="#Remote_TLS_server_certificates">setting up the
|
||||
server certificate</a> so here we just briefly cover the
|
||||
steps.
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
Make a private key:
|
||||
<pre>
|
||||
certtool --generate-privkey > clientkey.pem
|
||||
</pre>
|
||||
</li>
|
||||
<li>
|
||||
Act as CA and sign the certificate. Create client.info containing:
|
||||
<pre>
|
||||
country = GB
|
||||
state = London
|
||||
locality = London
|
||||
organization = Libvirt Project
|
||||
cn = client1
|
||||
tls_www_client
|
||||
encryption_key
|
||||
signing_key
|
||||
</pre>
|
||||
and sign by doing:
|
||||
<pre>
|
||||
certtool --generate-certificate --load-privkey clientkey.pem \
|
||||
--load-ca-certificate cacert.pem --load-ca-privkey cakey.pem \
|
||||
--template client.info --outfile clientcert.pem
|
||||
</pre>
|
||||
</li>
|
||||
<li>
|
||||
Install the certificates on the client machine:
|
||||
<pre>
|
||||
cp clientkey.pem /etc/pki/libvirt/private/clientkey.pem
|
||||
cp clientcert.pem /etc/pki/libvirt/clientcert.pem
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
<h2>
|
||||
<a id="Remote_TLS_troubleshooting">Troubleshooting TLS certificate problems</a>
|
||||
</h2>
|
||||
<dl>
|
||||
<dt> failed to verify client's certificate </dt>
|
||||
<dd>
|
||||
<p>
|
||||
On the server side, run the libvirtd server with
|
||||
the '--listen' and '--verbose' options while the
|
||||
client is connecting. The verbose log messages should
|
||||
tell you enough to diagnose the problem.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p> You can use the virt-pki-validate shell script
|
||||
to analyze the setup on the client or server machines, preferably as root.
|
||||
It will try to point out the possible problems and provide solutions to
|
||||
fix the set up up to a point where you have secure remote access.</p>
|
||||
</body>
|
||||
</html>
|
331
docs/tlscerts.rst
Normal file
331
docs/tlscerts.rst
Normal file
@ -0,0 +1,331 @@
|
||||
==========================
|
||||
TLS x509 certificate setup
|
||||
==========================
|
||||
|
||||
.. contents::
|
||||
|
||||
Public Key Infrastructure set up
|
||||
--------------------------------
|
||||
|
||||
If you are unsure how to create TLS certificates, skip to the next section.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Location
|
||||
- Machine
|
||||
- Description
|
||||
- Required fields
|
||||
|
||||
* - ``/etc/pki/CA/cacert.pem``
|
||||
- Installed on the client and server
|
||||
- CA's certificate
|
||||
- n/a
|
||||
|
||||
* - ``$HOME/.pki/cacert.pem``
|
||||
- Installed on the client
|
||||
- CA's certificate
|
||||
- n/a
|
||||
|
||||
* - ``/etc/pki/libvirt/private/serverkey.pem``
|
||||
- Installed on the server
|
||||
- Server's private key
|
||||
- n/a
|
||||
|
||||
* - ``/etc/pki/libvirt/servercert.pem``
|
||||
- Installed on the server
|
||||
- Server's certificate signed by the CA
|
||||
- CommonName (CN) must be the hostname of the server as it is seen by
|
||||
clients. All hostname and IP address variants that might be used to
|
||||
reach the server should be listed in Subject Alt Name fields.
|
||||
|
||||
* - ``/etc/pki/libvirt/private/clientkey.pem``
|
||||
- Installed on the client
|
||||
- Client's private key
|
||||
- n/a
|
||||
|
||||
* - ``/etc/pki/libvirt/clientcert.pem``
|
||||
- Installed on the client
|
||||
- Client's certificate signed by the CA
|
||||
- Distinguished Name (DN) can be checked against an access control list
|
||||
(``tls_allowed_dn_list``).
|
||||
|
||||
* - ``$HOME/.pki/libvirt/clientkey.pem``
|
||||
- Installed on the client
|
||||
- Client's private key
|
||||
- n/a
|
||||
|
||||
* - ``$HOME/.pki/libvirt/clientcert.pem``
|
||||
- Installed on the client
|
||||
- Client's certificate signed by the CA
|
||||
(`more info <#Remote_TLS_client_certificates>`__)
|
||||
- Distinguished Name (DN) can be checked against an access control list
|
||||
(``tls_allowed_dn_list``).
|
||||
|
||||
If 'pkipath' is specified in URI, then all the client certificates must be found
|
||||
in the path specified, otherwise the connection will fail with a fatal error. If
|
||||
'pkipath' is not specified:
|
||||
|
||||
- For a non-root user, libvirt tries to find the certificates in
|
||||
$HOME/.pki/libvirt first. If the required CA certificate cannot be found,
|
||||
then the global default location (/etc/pki/CA/cacert.pem) will be used.
|
||||
Likewise, if either the client certificate or the client key cannot be found,
|
||||
then the global default locations (/etc/pki/libvirt/clientcert.pem,
|
||||
/etc/pki/libvirt/private/clientkey.pem) will be used.
|
||||
|
||||
- For the root user, the global default locations will always be used.
|
||||
|
||||
Background to TLS certificates
|
||||
------------------------------
|
||||
|
||||
Libvirt supports TLS certificates for verifying the identity of the server and
|
||||
clients. There are two distinct checks involved:
|
||||
|
||||
- The client should know that it is connecting to the right server. Checking
|
||||
done by client by matching the certificate that the server sends to the
|
||||
server's hostname. May be disabled by adding ``?no_verify=1`` to the `remote
|
||||
URI <uri.html#Remote_URI_parameters>`__.
|
||||
|
||||
- The server should know that only permitted clients are connecting. This can
|
||||
be done based on client's IP address, or on client's IP address and client's
|
||||
certificate. Checking done by the server. May be enabled and disabled in the
|
||||
`libvirtd.conf file <remote.html#Remote_libvirtd_configuration>`__.
|
||||
|
||||
For full certificate checking you will need to have certificates issued by a
|
||||
recognised `Certificate Authority
|
||||
(CA) <https://en.wikipedia.org/wiki/Certificate_authority>`__ for your server(s)
|
||||
and all clients. To avoid the expense of getting certificates from a commercial
|
||||
CA, you can set up your own CA and tell your server(s) and clients to trust
|
||||
certificates issues by your own CA. Follow the instructions in the next section.
|
||||
|
||||
Be aware that the `default configuration for
|
||||
libvirtd <remote.html#Remote_libvirtd_configuration>`__ allows any client to
|
||||
connect provided they have a valid certificate issued by the CA for their own IP
|
||||
address. You may want to change this to make it less (or more) permissive,
|
||||
depending on your needs.
|
||||
|
||||
Setting up a Certificate Authority (CA)
|
||||
---------------------------------------
|
||||
|
||||
You will need the `GnuTLS certtool program documented
|
||||
here <https://www.gnutls.org/manual/html_node/certtool-Invocation.html>`__. In
|
||||
Fedora, it is in the ``gnutls-utils`` package.
|
||||
|
||||
Create a private key for your CA:
|
||||
|
||||
::
|
||||
|
||||
certtool --generate-privkey > cakey.pem
|
||||
|
||||
and self-sign it by creating a file with the signature details called
|
||||
``ca.info`` containing:
|
||||
|
||||
::
|
||||
|
||||
cn = Name of your organization
|
||||
ca
|
||||
cert_signing_key
|
||||
|
||||
::
|
||||
|
||||
certtool --generate-self-signed --load-privkey cakey.pem \
|
||||
--template ca.info --outfile cacert.pem
|
||||
|
||||
(You can delete ``ca.info`` file now if you want).
|
||||
|
||||
Now you have two files which matter:
|
||||
|
||||
- ``cakey.pem`` - Your CA's private key (keep this very secret!)
|
||||
|
||||
- ``cacert.pem`` - Your CA's certificate (this is public).
|
||||
|
||||
``cacert.pem`` has to be installed on clients and server(s) to let them know
|
||||
that they can trust certificates issued by your CA.
|
||||
|
||||
The normal installation directory for ``cacert.pem`` is
|
||||
``/etc/pki/CA/cacert.pem`` on all clients and servers.
|
||||
|
||||
To see the contents of this file, do:
|
||||
|
||||
::
|
||||
|
||||
certtool -i --infile cacert.pem
|
||||
|
||||
X.509 certificate info:
|
||||
|
||||
Version: 3
|
||||
Serial Number (hex): 00
|
||||
Subject: CN=Libvirt Project
|
||||
Issuer: CN=Libvirt Project
|
||||
Signature Algorithm: RSA-SHA
|
||||
Validity:
|
||||
Not Before: Mon Jun 18 16:22:18 2007
|
||||
Not After: Tue Jun 17 16:22:18 2008
|
||||
[etc]
|
||||
|
||||
This is all that is required to set up your CA. Keep the CA's private key
|
||||
carefully as you will need it when you come to issue certificates for your
|
||||
clients and servers.
|
||||
|
||||
Issuing server certificates
|
||||
---------------------------
|
||||
|
||||
For each server (libvirtd) you need to issue a certificate containing one or
|
||||
more hostnames and/or IP addresses. Historically the CommonName (CN) field would
|
||||
contain the hostname of the server and would match the hostname used in the URI
|
||||
that clients pass to libvirt. In most TLS implementations the CN field is
|
||||
considered legacy data. The preferential mechanism is to use Subject Alt Name
|
||||
(SAN) extension fields to validate against. In the future use of the CN field
|
||||
for validation may be discontinued entirely, so it is strongly recommended to
|
||||
include the SAN fields.
|
||||
|
||||
In the example below, clients will be connecting to the server using a
|
||||
`URI <uri.html#URI_remote>`__ of ``qemu://compute1.libvirt.org/system``, so the
|
||||
CN must be "``compute1.libvirt.org``".
|
||||
|
||||
Make a private key for the server:
|
||||
|
||||
::
|
||||
|
||||
certtool --generate-privkey > serverkey.pem
|
||||
|
||||
and sign that key with the CA's private key by first creating a template file
|
||||
called ``server.info``. The template file will contain a number of fields to
|
||||
define the server as follows:
|
||||
|
||||
::
|
||||
|
||||
organization = Name of your organization
|
||||
cn = compute1.libvirt.org
|
||||
dns_name = compute1
|
||||
dns_name = compute1.libvirt.org
|
||||
ip_address = 10.0.0.74
|
||||
ip_address = 192.168.1.24
|
||||
ip_address = 2001:cafe::74
|
||||
ip_address = fe20::24
|
||||
tls_www_server
|
||||
encryption_key
|
||||
signing_key
|
||||
|
||||
The 'cn' field should refer to the fully qualified public hostname of the
|
||||
server. For the SAN extension data, there must also be one or more 'dns_name'
|
||||
fields that contain all possible hostnames that can be reasonably used by
|
||||
clients to reach the server, both with and without domain name qualifiers. If
|
||||
clients are likely to connect to the server by IP address, then one or more
|
||||
'ip_address' fields should also be added.
|
||||
|
||||
Use the template file as input to a ``certtool`` command to sign the server
|
||||
certificate:
|
||||
|
||||
::
|
||||
|
||||
certtool --generate-certificate --load-privkey serverkey.pem \
|
||||
--load-ca-certificate cacert.pem --load-ca-privkey cakey.pem \
|
||||
--template server.info --outfile servercert.pem
|
||||
|
||||
This gives two files:
|
||||
|
||||
- ``serverkey.pem`` - The server's private key.
|
||||
|
||||
- ``servercert.pem`` - The server's public key.
|
||||
|
||||
We can examine this certificate and its signature:
|
||||
|
||||
::
|
||||
|
||||
certtool -i --infile servercert.pem
|
||||
X.509 certificate info:
|
||||
|
||||
Version: 3
|
||||
Serial Number (hex): 00
|
||||
Subject: O=Libvirt Project,CN=compute1.libvirt.org
|
||||
Issuer: CN=Libvirt Project
|
||||
Signature Algorithm: RSA-SHA
|
||||
Validity:
|
||||
Not Before: Wed Oct 04 09:09:44 UTC 2017
|
||||
Not After: Thu Oct 04 09:09:44 UTC 2018
|
||||
Extensions:
|
||||
Basic Constraints (critical):
|
||||
Certificate Authority (CA): FALSE
|
||||
Subject Alternative Name (not critical):
|
||||
DNSname: compute1
|
||||
DNSname: compute1.libvirt.org
|
||||
IPAddress: 10.0.0.74
|
||||
IPAddress: 192.168.1.24
|
||||
IPAddress: 2001:cafe::74
|
||||
IPAddress: fe20::24
|
||||
|
||||
Note the "Issuer" CN is "Libvirt Project" (the CA) and the "Subject" CN is
|
||||
"compute1.libvirt.org" (the server). Notice that the hostname listed in the CN
|
||||
must also be duplicated as a DNSname entry
|
||||
|
||||
Finally we have two files to install:
|
||||
|
||||
- ``serverkey.pem`` is the server's private key which should be copied to the
|
||||
server *only* as ``/etc/pki/libvirt/private/serverkey.pem``.
|
||||
|
||||
- ``servercert.pem`` is the server's certificate which can be installed on the
|
||||
server as ``/etc/pki/libvirt/servercert.pem``.
|
||||
|
||||
Issuing client certificates
|
||||
---------------------------
|
||||
|
||||
For each client (ie. any program linked with libvirt, such as
|
||||
`virt-manager <https://virt-manager.org/>`__) you need to issue a certificate
|
||||
with the X.509 Distinguished Name (DN) set to a suitable name. You can decide
|
||||
this on a company / organisation policy. For example:
|
||||
|
||||
::
|
||||
|
||||
C=GB,ST=London,L=London,O=Libvirt Project,CN=name_of_client
|
||||
|
||||
The process is the same as for `setting up the server
|
||||
certificate <#Remote_TLS_server_certificates>`__ so here we just briefly cover
|
||||
the steps.
|
||||
|
||||
#. Make a private key:
|
||||
|
||||
::
|
||||
|
||||
certtool --generate-privkey > clientkey.pem
|
||||
|
||||
#. Act as CA and sign the certificate. Create client.info containing:
|
||||
|
||||
::
|
||||
|
||||
country = GB
|
||||
state = London
|
||||
locality = London
|
||||
organization = Libvirt Project
|
||||
cn = client1
|
||||
tls_www_client
|
||||
encryption_key
|
||||
signing_key
|
||||
|
||||
and sign by doing:
|
||||
|
||||
::
|
||||
|
||||
certtool --generate-certificate --load-privkey clientkey.pem \
|
||||
--load-ca-certificate cacert.pem --load-ca-privkey cakey.pem \
|
||||
--template client.info --outfile clientcert.pem
|
||||
|
||||
#. Install the certificates on the client machine:
|
||||
|
||||
::
|
||||
|
||||
cp clientkey.pem /etc/pki/libvirt/private/clientkey.pem
|
||||
cp clientcert.pem /etc/pki/libvirt/clientcert.pem
|
||||
|
||||
Troubleshooting TLS certificate problems
|
||||
----------------------------------------
|
||||
|
||||
failed to verify client's certificate
|
||||
On the server side, run the libvirtd server with the '--listen' and
|
||||
'--verbose' options while the client is connecting. The verbose log messages
|
||||
should tell you enough to diagnose the problem.
|
||||
|
||||
You can use the virt-pki-validate shell script to analyze the setup on the
|
||||
client or server machines, preferably as root. It will try to point out the
|
||||
possible problems and provide solutions to fix the set up up to a point where
|
||||
you have secure remote access.
|
Loading…
Reference in New Issue
Block a user