This patch extends bootstrap.py to not only create the cluster certificate but also the master node's client certificate.
Signed-off-by: Helga Velroyen <[email protected]> --- lib/bootstrap.py | 16 ++++++++++++++-- lib/client/gnt_cluster.py | 5 ++++- lib/cmdlib/cluster.py | 2 -- lib/utils/security.py | 20 +++++++++++++++++++- tools/cfgupgrade | 9 ++++++++- 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/lib/bootstrap.py b/lib/bootstrap.py index 7468361..a9b1f68 100644 --- a/lib/bootstrap.py +++ b/lib/bootstrap.py @@ -104,10 +104,12 @@ def GenerateHmacKey(file_name): # pylint: disable=R0913 def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert, - new_confd_hmac_key, new_cds, + new_confd_hmac_key, new_cds, new_client_cert, + master_name, rapi_cert_pem=None, spice_cert_pem=None, spice_cacert_pem=None, cds=None, nodecert_file=pathutils.NODED_CERT_FILE, + clientcert_file=pathutils.NODED_CLIENT_CERT_FILE, rapicert_file=pathutils.RAPI_CERT_FILE, spicecert_file=pathutils.SPICE_CERT_FILE, spicecacert_file=pathutils.SPICE_CACERT_FILE, @@ -125,6 +127,10 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert, @param new_confd_hmac_key: Whether to generate a new HMAC key @type new_cds: bool @param new_cds: Whether to generate a new cluster domain secret + @type new_client_cert: bool + @param new_client_cert: Whether to generate a new client certificate + @type master_name: string + @param master_name: FQDN of the master node @type rapi_cert_pem: string @param rapi_cert_pem: New RAPI certificate in PEM format @type spice_cert_pem: string @@ -152,6 +158,12 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert, new_cluster_cert, nodecert_file, 1, "Generating new cluster certificate at %s" % nodecert_file) + # If the cluster certificate was renewed, the client cert has to be + # renewed and resigned. + if new_cluster_cert or new_client_cert: + utils.GenerateNewClientSslCert(clientcert_file, nodecert_file, + master_name) + # confd HMAC key if new_confd_hmac_key or not os.path.exists(hmackey_file): logging.debug("Writing new confd HMAC key to %s", hmackey_file) @@ -213,7 +225,7 @@ def _InitGanetiServerSetup(master_name): """ # Generate cluster secrets - GenerateClusterCrypto(True, False, False, False, False) + GenerateClusterCrypto(True, False, False, False, False, False, master_name) result = utils.RunCmd([pathutils.DAEMON_UTIL, "start", constants.NODED]) if result.failed: diff --git a/lib/client/gnt_cluster.py b/lib/client/gnt_cluster.py index 5afbdda..c4bbd09 100644 --- a/lib/client/gnt_cluster.py +++ b/lib/client/gnt_cluster.py @@ -1018,12 +1018,15 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, # pylint: disable=R0911 def _RenewCryptoInner(ctx): ctx.feedback_fn("Updating certificates and keys") - # Note: the node certificate will be generated in the LU + + master_name = ssconf.SimpleStore().GetMasterNode() bootstrap.GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert, new_confd_hmac_key, new_cds, + True, # new client certificate for master + master_name, rapi_cert_pem=rapi_cert_pem, spice_cert_pem=spice_cert_pem, spice_cacert_pem=spice_cacert_pem, diff --git a/lib/cmdlib/cluster.py b/lib/cmdlib/cluster.py index c010026..0251525 100644 --- a/lib/cmdlib/cluster.py +++ b/lib/cmdlib/cluster.py @@ -390,8 +390,6 @@ class LUClusterPostInit(LogicalUnit): self.master_ndparams.get(constants.ND_OVS_LINK, None)) result.Raise("Could not successully configure Open vSwitch") - _UpdateMasterClientCert(self, self.cfg, self.master_uuid) - return True diff --git a/lib/utils/security.py b/lib/utils/security.py index 7127e8b..bf366b2 100644 --- a/lib/utils/security.py +++ b/lib/utils/security.py @@ -35,6 +35,7 @@ import logging import OpenSSL import os import uuid as uuid_module +import time from ganeti.utils import io from ganeti.utils import x509 @@ -60,7 +61,7 @@ def GetCertificateDigest(cert_filename=pathutils.NODED_CLIENT_CERT_FILE): def GenerateNewSslCert(new_cert, cert_filename, serial_no, log_msg, uid=-1, gid=-1): - """Creates a new SSL certificate and backups the old one. + """Creates a new server SSL certificate and backups the old one. @type new_cert: boolean @param new_cert: whether a new certificate should be created @@ -85,6 +86,23 @@ def GenerateNewSslCert(new_cert, cert_filename, serial_no, log_msg, x509.GenerateSelfSignedSslCert(cert_filename, serial_no, uid=uid, gid=gid) +def GenerateNewClientSslCert(cert_filename, signing_cert_filename, + hostname): + """Creates a new server SSL certificate and backups the old one. + + @type cert_filename: string + @param cert_filename: filename of the certificate file + @type signing_cert_filename: string + @param signing_cert_filename: name of the certificate to be used for signing + @type hostname: string + @param hostname: name of the machine whose cert is created + + """ + serial_no = int(time.time()) + x509.GenerateSignedSslCert(cert_filename, serial_no, signing_cert_filename, + common_name=hostname) + + def VerifyCertificate(filename): """Verifies a SSL certificate. diff --git a/tools/cfgupgrade b/tools/cfgupgrade index a42b94a..9c2775d 100755 --- a/tools/cfgupgrade +++ b/tools/cfgupgrade @@ -784,8 +784,15 @@ def main(): backup=True) if not options.dry_run: + # This creates the cluster certificate if it does not exist yet. + # In this case, we do not automatically create a client certificate + # as well, because if the cluster certificate did not exist before, + # no client certificate will exist on any node yet. In this case + # all client certificate should be renewed by 'gnt-cluster + # renew-crypto --new-node-certificates'. This will be enforced + # by a nagging warning in 'gnt-cluster verify'. bootstrap.GenerateClusterCrypto( - False, False, False, False, False, + False, False, False, False, False, False, None, nodecert_file=options.SERVER_PEM_PATH, rapicert_file=options.RAPI_CERT_FILE, spicecert_file=options.SPICE_CERT_FILE, -- 2.4.3.573.g4eafbef
