Commit 60cc531d authored by Helga Velroyen's avatar Helga Velroyen

Create client SSL certificates on cluster init

This patch makes Ganeti create a client SSL certificate for
the master node on cluster initialization. Note that some of
the code in this patch is later moved into an LU to serve
requirements for crypto renewal and updates, but for this
point in the patch series it makes sense to add it here.
Signed-off-by: default avatarHelga Velroyen <helgav@google.com>
Reviewed-by: default avatarHrvoje Ribicic <riba@google.com>
parent 1059337d
......@@ -92,10 +92,11 @@ def GenerateHmacKey(file_name):
def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert,
new_confd_hmac_key, new_cds,
new_confd_hmac_key, new_cds, new_node_client_cert,
rapi_cert_pem=None, spice_cert_pem=None,
spice_cacert_pem=None, cds=None,
nodecert_file=pathutils.NODED_CERT_FILE,
nodecert_client_file=pathutils.NODED_CLIENT_CERT_FILE,
rapicert_file=pathutils.RAPI_CERT_FILE,
spicecert_file=pathutils.SPICE_CERT_FILE,
spicecacert_file=pathutils.SPICE_CACERT_FILE,
......@@ -113,6 +114,9 @@ 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_node_client_cert: bool
@param new_node_client_cert: Whether to generate a new node (SSL)
client certificate
@type rapi_cert_pem: string
@param rapi_cert_pem: New RAPI certificate in PEM format
@type spice_cert_pem: string
......@@ -124,6 +128,9 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert,
@param cds: New cluster domain secret
@type nodecert_file: string
@param nodecert_file: optional override of the node cert file path
@type nodecert_client_file: string
@param nodecert_client_file: optional override of the node client certificate
file path
@type rapicert_file: string
@param rapicert_file: optional override of the rapi cert file path
@type spicecert_file: string
......@@ -135,33 +142,29 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert,
"""
# noded SSL certificate
cluster_cert_exists = os.path.exists(nodecert_file)
if new_cluster_cert or not cluster_cert_exists:
if cluster_cert_exists:
utils.CreateBackup(nodecert_file)
utils.GenerateNewSslCert(
new_cluster_cert, nodecert_file,
"Generating new cluster certificate at %s" % nodecert_file)
logging.debug("Generating new cluster certificate at %s", nodecert_file)
utils.GenerateSelfSignedSslCert(nodecert_file)
# noded client SSL certificate (to be used only by this very node)
utils.GenerateNewSslCert(
new_node_client_cert, nodecert_client_file,
"Generating new node client certificate at %s" % nodecert_client_file)
# 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)
GenerateHmacKey(hmackey_file)
# RAPI
rapi_cert_exists = os.path.exists(rapicert_file)
if rapi_cert_pem:
# Assume rapi_pem contains a valid PEM-formatted certificate and key
logging.debug("Writing RAPI certificate at %s", rapicert_file)
utils.WriteFile(rapicert_file, data=rapi_cert_pem, backup=True)
elif new_rapi_cert or not rapi_cert_exists:
if rapi_cert_exists:
utils.CreateBackup(rapicert_file)
logging.debug("Generating new RAPI certificate at %s", rapicert_file)
utils.GenerateSelfSignedSslCert(rapicert_file)
else:
utils.GenerateNewSslCert(
new_rapi_cert, rapicert_file,
"Generating new RAPI certificate at %s" % rapicert_file)
# SPICE
spice_cert_exists = os.path.exists(spicecert_file)
......@@ -209,7 +212,7 @@ def _InitGanetiServerSetup(master_name):
"""
# Generate cluster secrets
GenerateClusterCrypto(True, False, False, False, False)
GenerateClusterCrypto(True, False, False, False, False, True)
result = utils.RunCmd([pathutils.DAEMON_UTIL, "start", constants.NODED])
if result.failed:
......
......@@ -961,11 +961,13 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, # pylint: disable=R0911
def _RenewCryptoInner(ctx):
ctx.feedback_fn("Updating certificates and keys")
# FIXME: add separate option for client certs
bootstrap.GenerateClusterCrypto(new_cluster_cert,
new_rapi_cert,
new_spice_cert,
new_confd_hmac_key,
new_cds,
new_cluster_cert,
rapi_cert_pem=rapi_cert_pem,
spice_cert_pem=spice_cert_pem,
spice_cacert_pem=spice_cacert_pem,
......
......@@ -106,6 +106,7 @@ RESTRICTED_COMMANDS_DIR = CONF_DIR + "/restricted-commands"
#: Node daemon certificate path
NODED_CERT_FILE = DATA_DIR + "/server.pem"
NODED_CLIENT_CERT_FILE = DATA_DIR + "/client.pem"
#: Node daemon certificate file permissions
NODED_CERT_MODE = 0440
......
......@@ -24,8 +24,10 @@
import logging
import OpenSSL
import os
from ganeti.utils import io
from ganeti.utils import x509
from ganeti import pathutils
......@@ -92,3 +94,23 @@ def GetClientCertificateDigest(cert_filename=pathutils.NODED_CERT_FILE):
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
cert_plain)
return cert.digest("sha1")
def GenerateNewSslCert(new_cert, cert_filename, log_msg):
"""Creates a new SSL certificate and backups the old one.
@type new_cert: boolean
@param new_cert: whether a new certificate should be created
@type cert_filename: string
@param cert_filename: filename of the certificate file
@type log_msg: string
@param log_msg: log message to be written on certificate creation
"""
cert_exists = os.path.exists(cert_filename)
if new_cert or not cert_exists:
if cert_exists:
io.CreateBackup(cert_filename)
logging.debug(log_msg)
x509.GenerateSelfSignedSslCert(cert_filename)
......@@ -571,8 +571,9 @@ def main():
backup=True)
if not options.dry_run:
# FIXME: fix node client certificate
bootstrap.GenerateClusterCrypto(
False, False, False, False, False,
False, False, False, False, False, False,
nodecert_file=options.SERVER_PEM_PATH,
rapicert_file=options.RAPI_CERT_FILE,
spicecert_file=options.SPICE_CERT_FILE,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment