Init: create the master's client cert in bootstrap
authorHelga Velroyen <helgav@google.com>
Tue, 9 Jun 2015 15:56:09 +0000 (17:56 +0200)
committerHelga Velroyen <helgav@google.com>
Mon, 6 Jul 2015 10:45:53 +0000 (12:45 +0200)
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 <helgav@google.com>
Reviewed-by: Klaus Aehlig <aehlig@google.com>

lib/bootstrap.py
lib/client/gnt_cluster.py
lib/cmdlib/cluster.py
lib/utils/security.py
tools/cfgupgrade
tools/post-upgrade

index 7468361..a9b1f68 100644 (file)
@@ -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:
index 54f0d35..0d14de6 100644 (file)
@@ -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,
index c010026..0251525 100644 (file)
@@ -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
 
 
index 7127e8b..bf366b2 100644 (file)
@@ -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.
 
index a42b94a..9c2775d 100755 (executable)
@@ -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,
index f3a1132..4ab460d 100644 (file)
@@ -51,7 +51,7 @@ def main():
 
   version = utils.version.ParseVersion(versionstring)
 
-  if utils.version.IsBefore(version, 2, 11, 0):
+  if utils.version.IsBefore(version, 2, 12, 5):
     result = utils.RunCmd(["gnt-cluster", "renew-crypto",
                            "--new-node-certificates", "-f"])
     if result.failed: