Statistics
| Branch: | Tag: | Revision:

root / doc / design-x509-ca.rst @ 7fa310f6

History | View | Annotate | Download (6.4 kB)

1 539f195a Michael Hanselmann
=======================================
2 539f195a Michael Hanselmann
Design for a X509 Certificate Authority
3 539f195a Michael Hanselmann
=======================================
4 539f195a Michael Hanselmann
5 539f195a Michael Hanselmann
.. contents:: :depth: 4
6 539f195a Michael Hanselmann
7 539f195a Michael Hanselmann
Current state and shortcomings
8 539f195a Michael Hanselmann
------------------------------
9 539f195a Michael Hanselmann
10 539f195a Michael Hanselmann
Import/export in Ganeti have a need for many unique X509 certificates.
11 539f195a Michael Hanselmann
So far these were all self-signed, but with the :doc:`new design for
12 539f195a Michael Hanselmann
import/export <design-impexp2>` they need to be signed by a Certificate
13 539f195a Michael Hanselmann
Authority (CA).
14 539f195a Michael Hanselmann
15 539f195a Michael Hanselmann
16 539f195a Michael Hanselmann
Proposed changes
17 539f195a Michael Hanselmann
----------------
18 539f195a Michael Hanselmann
19 539f195a Michael Hanselmann
The plan is to implement a simple CA in Ganeti.
20 539f195a Michael Hanselmann
21 539f195a Michael Hanselmann
Interacting with an external CA is too difficult or impossible for
22 539f195a Michael Hanselmann
automated processes like exporting instances, so each Ganeti cluster
23 539f195a Michael Hanselmann
will have its own CA. The public key will be stored in
24 539f195a Michael Hanselmann
``…/lib/ganeti/ca/cert.pem``, the private key (only readable by the
25 539f195a Michael Hanselmann
master daemon) in ``…/lib/ganeti/ca/key.pem``.
26 539f195a Michael Hanselmann
27 539f195a Michael Hanselmann
Similar to the RAPI certificate, a new CA certificate can be installed
28 539f195a Michael Hanselmann
using the ``gnt-cluster renew-crypto`` command. Such a CA could be an
29 539f195a Michael Hanselmann
intermediate of a third-party CA. By default a self-signed CA is
30 539f195a Michael Hanselmann
generated and used.
31 539f195a Michael Hanselmann
32 539f195a Michael Hanselmann
.. _x509-ca-serial:
33 539f195a Michael Hanselmann
34 539f195a Michael Hanselmann
Each certificate signed by the CA is required to have a unique serial
35 539f195a Michael Hanselmann
number. The serial number is stored in the file
36 539f195a Michael Hanselmann
``…/lib/ganeti/ca/serial``, replicated to all master candidates and
37 539f195a Michael Hanselmann
never reset, even when a new CA is installed.
38 539f195a Michael Hanselmann
39 539f195a Michael Hanselmann
The threat model is expected to be the same as with self-signed
40 539f195a Michael Hanselmann
certificates. To reinforce this, all certificates signed by the CA must
41 539f195a Michael Hanselmann
be valid for less than one week (168 hours).
42 539f195a Michael Hanselmann
43 539f195a Michael Hanselmann
Implementing support for Certificate Revocation Lists (CRL) using
44 539f195a Michael Hanselmann
OpenSSL is non-trivial. Lighttpd doesn't support them at all and
45 539f195a Michael Hanselmann
`apparently never will in version 1.4.x
46 539f195a Michael Hanselmann
<http://redmine.lighttpd.net/issues/2278>`_. Some CRL-related parts have
47 539f195a Michael Hanselmann
only been added in the most recent version of pyOpenSSL (0.11). Instead
48 539f195a Michael Hanselmann
of a CRL, Ganeti will gain a new cluster configuration property defining
49 539f195a Michael Hanselmann
the minimum accepted serial number. In case of a lost or compromised
50 539f195a Michael Hanselmann
private key this property can be set to the most recently generated
51 539f195a Michael Hanselmann
serial number.
52 539f195a Michael Hanselmann
53 539f195a Michael Hanselmann
While possible to implement in the future, other X509 certificates used
54 539f195a Michael Hanselmann
by the cluster (e.g. RAPI or inter-node communication) will not be
55 539f195a Michael Hanselmann
automatically signed by the per-cluster CA.
56 539f195a Michael Hanselmann
57 539f195a Michael Hanselmann
The ``commonName`` attribute of signed certificates must be set to the
58 539f195a Michael Hanselmann
the cluster name or the name of a node in the cluster.
59 539f195a Michael Hanselmann
60 539f195a Michael Hanselmann
61 539f195a Michael Hanselmann
Software requirements
62 539f195a Michael Hanselmann
---------------------
63 539f195a Michael Hanselmann
64 539f195a Michael Hanselmann
- pyOpenSSL 0.10 or above (lower versions can't set the X509v3 extension
65 539f195a Michael Hanselmann
  ``subjectKeyIdentifier`` recommended for certificate authority
66 539f195a Michael Hanselmann
  certificates by :rfc:`3280`, section 4.2.1.2)
67 539f195a Michael Hanselmann
68 539f195a Michael Hanselmann
69 539f195a Michael Hanselmann
Code samples
70 539f195a Michael Hanselmann
------------
71 539f195a Michael Hanselmann
72 539f195a Michael Hanselmann
Generating X509 CA using pyOpenSSL
73 539f195a Michael Hanselmann
++++++++++++++++++++++++++++++++++
74 539f195a Michael Hanselmann
75 539f195a Michael Hanselmann
.. highlight:: python
76 539f195a Michael Hanselmann
77 539f195a Michael Hanselmann
The following code sample shows how to generate a CA certificate using
78 539f195a Michael Hanselmann
pyOpenSSL::
79 539f195a Michael Hanselmann
80 539f195a Michael Hanselmann
  key = OpenSSL.crypto.PKey()
81 539f195a Michael Hanselmann
  key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
82 539f195a Michael Hanselmann
83 539f195a Michael Hanselmann
  ca = OpenSSL.crypto.X509()
84 539f195a Michael Hanselmann
  ca.set_version(3)
85 539f195a Michael Hanselmann
  ca.set_serial_number(1)
86 539f195a Michael Hanselmann
  ca.get_subject().CN = "ca.example.com"
87 539f195a Michael Hanselmann
  ca.gmtime_adj_notBefore(0)
88 539f195a Michael Hanselmann
  ca.gmtime_adj_notAfter(24 * 60 * 60)
89 539f195a Michael Hanselmann
  ca.set_issuer(ca.get_subject())
90 539f195a Michael Hanselmann
  ca.set_pubkey(key)
91 539f195a Michael Hanselmann
  ca.add_extensions([
92 539f195a Michael Hanselmann
    OpenSSL.crypto.X509Extension("basicConstraints", True,
93 539f195a Michael Hanselmann
                                 "CA:TRUE, pathlen:0"),
94 539f195a Michael Hanselmann
    OpenSSL.crypto.X509Extension("keyUsage", True,
95 539f195a Michael Hanselmann
                                 "keyCertSign, cRLSign"),
96 539f195a Michael Hanselmann
    OpenSSL.crypto.X509Extension("subjectKeyIdentifier", False, "hash",
97 539f195a Michael Hanselmann
                                 subject=ca),
98 539f195a Michael Hanselmann
    ])
99 539f195a Michael Hanselmann
  ca.sign(key, "sha1")
100 539f195a Michael Hanselmann
101 539f195a Michael Hanselmann
102 539f195a Michael Hanselmann
Signing X509 certificate using CA
103 539f195a Michael Hanselmann
+++++++++++++++++++++++++++++++++
104 539f195a Michael Hanselmann
105 539f195a Michael Hanselmann
.. highlight:: python
106 539f195a Michael Hanselmann
107 539f195a Michael Hanselmann
The following code sample shows how to sign an X509 certificate using a
108 539f195a Michael Hanselmann
CA::
109 539f195a Michael Hanselmann
110 539f195a Michael Hanselmann
  ca_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
111 539f195a Michael Hanselmann
                                            "ca.pem")
112 539f195a Michael Hanselmann
  ca_key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
113 539f195a Michael Hanselmann
                                          "ca.pem")
114 539f195a Michael Hanselmann
115 539f195a Michael Hanselmann
  key = OpenSSL.crypto.PKey()
116 539f195a Michael Hanselmann
  key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
117 539f195a Michael Hanselmann
118 539f195a Michael Hanselmann
  cert = OpenSSL.crypto.X509()
119 539f195a Michael Hanselmann
  cert.get_subject().CN = "node1.example.com"
120 539f195a Michael Hanselmann
  cert.set_serial_number(1)
121 539f195a Michael Hanselmann
  cert.gmtime_adj_notBefore(0)
122 539f195a Michael Hanselmann
  cert.gmtime_adj_notAfter(24 * 60 * 60)
123 539f195a Michael Hanselmann
  cert.set_issuer(ca_cert.get_subject())
124 539f195a Michael Hanselmann
  cert.set_pubkey(key)
125 539f195a Michael Hanselmann
  cert.sign(ca_key, "sha1")
126 539f195a Michael Hanselmann
127 539f195a Michael Hanselmann
128 539f195a Michael Hanselmann
How to generate Certificate Signing Request
129 539f195a Michael Hanselmann
+++++++++++++++++++++++++++++++++++++++++++
130 539f195a Michael Hanselmann
131 539f195a Michael Hanselmann
.. highlight:: python
132 539f195a Michael Hanselmann
133 539f195a Michael Hanselmann
The following code sample shows how to generate an X509 Certificate
134 539f195a Michael Hanselmann
Request (CSR)::
135 539f195a Michael Hanselmann
136 539f195a Michael Hanselmann
  key = OpenSSL.crypto.PKey()
137 539f195a Michael Hanselmann
  key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
138 539f195a Michael Hanselmann
139 539f195a Michael Hanselmann
  req = OpenSSL.crypto.X509Req()
140 539f195a Michael Hanselmann
  req.get_subject().CN = "node1.example.com"
141 539f195a Michael Hanselmann
  req.set_pubkey(key)
142 539f195a Michael Hanselmann
  req.sign(key, "sha1")
143 539f195a Michael Hanselmann
144 539f195a Michael Hanselmann
  # Write private key
145 539f195a Michael Hanselmann
  print OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)
146 539f195a Michael Hanselmann
147 539f195a Michael Hanselmann
  # Write request
148 539f195a Michael Hanselmann
  print OpenSSL.crypto.dump_certificate_request(OpenSSL.crypto.FILETYPE_PEM, req)
149 539f195a Michael Hanselmann
150 539f195a Michael Hanselmann
151 539f195a Michael Hanselmann
X509 certificate from Certificate Signing Request
152 539f195a Michael Hanselmann
+++++++++++++++++++++++++++++++++++++++++++++++++
153 539f195a Michael Hanselmann
154 539f195a Michael Hanselmann
.. highlight:: python
155 539f195a Michael Hanselmann
156 539f195a Michael Hanselmann
The following code sample shows how to create an X509 certificate from a
157 539f195a Michael Hanselmann
Certificate Signing Request and sign it with a CA::
158 539f195a Michael Hanselmann
159 539f195a Michael Hanselmann
  ca_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
160 539f195a Michael Hanselmann
                                            "ca.pem")
161 539f195a Michael Hanselmann
  ca_key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
162 539f195a Michael Hanselmann
                                          "ca.pem")
163 539f195a Michael Hanselmann
  req = OpenSSL.crypto.load_certificate_request(OpenSSL.crypto.FILETYPE_PEM,
164 539f195a Michael Hanselmann
                                                open("req.csr").read())
165 539f195a Michael Hanselmann
166 539f195a Michael Hanselmann
  cert = OpenSSL.crypto.X509()
167 539f195a Michael Hanselmann
  cert.set_subject(req.get_subject())
168 539f195a Michael Hanselmann
  cert.set_serial_number(1)
169 539f195a Michael Hanselmann
  cert.gmtime_adj_notBefore(0)
170 539f195a Michael Hanselmann
  cert.gmtime_adj_notAfter(24 * 60 * 60)
171 539f195a Michael Hanselmann
  cert.set_issuer(ca_cert.get_subject())
172 539f195a Michael Hanselmann
  cert.set_pubkey(req.get_pubkey())
173 539f195a Michael Hanselmann
  cert.sign(ca_key, "sha1")
174 539f195a Michael Hanselmann
175 539f195a Michael Hanselmann
  print OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
176 539f195a Michael Hanselmann
177 539f195a Michael Hanselmann
178 539f195a Michael Hanselmann
Verify whether X509 certificate matches private key
179 539f195a Michael Hanselmann
+++++++++++++++++++++++++++++++++++++++++++++++++++
180 539f195a Michael Hanselmann
181 539f195a Michael Hanselmann
.. highlight:: python
182 539f195a Michael Hanselmann
183 539f195a Michael Hanselmann
The code sample below shows how to check whether a certificate matches
184 539f195a Michael Hanselmann
with a certain private key. OpenSSL has a function for this,
185 539f195a Michael Hanselmann
``X509_check_private_key``, but pyOpenSSL provides no access to it.
186 539f195a Michael Hanselmann
187 539f195a Michael Hanselmann
::
188 539f195a Michael Hanselmann
189 539f195a Michael Hanselmann
  ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
190 539f195a Michael Hanselmann
  ctx.use_privatekey(key)
191 539f195a Michael Hanselmann
  ctx.use_certificate(cert)
192 539f195a Michael Hanselmann
  try:
193 539f195a Michael Hanselmann
    ctx.check_privatekey()
194 539f195a Michael Hanselmann
  except OpenSSL.SSL.Error:
195 539f195a Michael Hanselmann
    print "Incorrect key"
196 539f195a Michael Hanselmann
  else:
197 539f195a Michael Hanselmann
    print "Key matches certificate"
198 539f195a Michael Hanselmann
199 539f195a Michael Hanselmann
200 539f195a Michael Hanselmann
.. vim: set textwidth=72 :
201 539f195a Michael Hanselmann
.. Local Variables:
202 539f195a Michael Hanselmann
.. mode: rst
203 539f195a Michael Hanselmann
.. fill-column: 72
204 539f195a Michael Hanselmann
.. End: