Commit 5916e61a authored by Andrea Spadaccini's avatar Andrea Spadaccini
Browse files

Merge branch 'devel-2.5'



* devel-2.5:
  Add tls_ciphers and use_vdagent options
  Updated man pages with new SPICE TLS options
  Implementation of TLS-protected SPICE connections
  Added SPICE TLS option and related cert paths
  Fix OS creation's error handling when pausing sync
Signed-off-by: default avatarAndrea Spadaccini <spadaccio@google.com>
Reviewed-by: default avatarMichael Hanselmann <hansmi@google.com>
parents 42d4d8b9 3e40b587
......@@ -196,6 +196,8 @@ def _BuildUploadFileList():
constants.SSH_KNOWN_HOSTS_FILE,
constants.VNC_PASSWORD_FILE,
constants.RAPI_CERT_FILE,
constants.SPICE_CERT_FILE,
constants.SPICE_CACERT_FILE,
constants.RAPI_USERS_FILE,
constants.CONFD_HMAC_KEY,
constants.CLUSTER_DOMAIN_SECRET_FILE,
......@@ -411,6 +413,8 @@ def LeaveCluster(modify_ssh_setup):
try:
utils.RemoveFile(constants.CONFD_HMAC_KEY)
utils.RemoveFile(constants.RAPI_CERT_FILE)
utils.RemoveFile(constants.SPICE_CERT_FILE)
utils.RemoveFile(constants.SPICE_CACERT_FILE)
utils.RemoveFile(constants.NODED_CERT_FILE)
except: # pylint: disable=W0702
logging.exception("Error while removing cluster secrets")
......
......@@ -88,10 +88,14 @@ def GenerateHmacKey(file_name):
backup=True)
def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_confd_hmac_key,
new_cds, rapi_cert_pem=None, cds=None,
def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_spice_cert,
new_confd_hmac_key, new_cds,
rapi_cert_pem=None, spice_cert_pem=None,
spice_cacert_pem=None, cds=None,
nodecert_file=constants.NODED_CERT_FILE,
rapicert_file=constants.RAPI_CERT_FILE,
spicecert_file=constants.SPICE_CERT_FILE,
spicecacert_file=constants.SPICE_CACERT_FILE,
hmackey_file=constants.CONFD_HMAC_KEY,
cds_file=constants.CLUSTER_DOMAIN_SECRET_FILE):
"""Updates the cluster certificates, keys and secrets.
......@@ -100,18 +104,29 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_confd_hmac_key,
@param new_cluster_cert: Whether to generate a new cluster certificate
@type new_rapi_cert: bool
@param new_rapi_cert: Whether to generate a new RAPI certificate
@type new_spice_cert: bool
@param new_spice_cert: Whether to generate a new SPICE certificate
@type new_confd_hmac_key: bool
@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 rapi_cert_pem: string
@param rapi_cert_pem: New RAPI certificate in PEM format
@type spice_cert_pem: string
@param spice_cert_pem: New SPICE certificate in PEM format
@type spice_cacert_pem: string
@param spice_cacert_pem: Certificate of the CA that signed the SPICE
certificate, in PEM format
@type cds: string
@param cds: New cluster domain secret
@type nodecert_file: string
@param nodecert_file: optional override of the node cert file path
@type rapicert_file: string
@param rapicert_file: optional override of the rapi cert file path
@type spicecert_file: string
@param spicecert_file: optional override of the spice cert file path
@type spicecacert_file: string
@param spicecacert_file: optional override of the spice CA cert file path
@type hmackey_file: string
@param hmackey_file: optional override of the hmac key file path
......@@ -145,6 +160,31 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_confd_hmac_key,
logging.debug("Generating new RAPI certificate at %s", rapicert_file)
utils.GenerateSelfSignedSslCert(rapicert_file)
# SPICE
spice_cert_exists = os.path.exists(spicecert_file)
spice_cacert_exists = os.path.exists(spicecacert_file)
if spice_cert_pem:
# spice_cert_pem implies also spice_cacert_pem
logging.debug("Writing SPICE certificate at %s", spicecert_file)
utils.WriteFile(spicecert_file, data=spice_cert_pem, backup=True)
logging.debug("Writing SPICE CA certificate at %s", spicecacert_file)
utils.WriteFile(spicecacert_file, data=spice_cacert_pem, backup=True)
elif new_spice_cert or not spice_cert_exists:
if spice_cert_exists:
utils.CreateBackup(spicecert_file)
if spice_cacert_exists:
utils.CreateBackup(spicecacert_file)
logging.debug("Generating new self-signed SPICE certificate at %s",
spicecert_file)
(_, cert_pem) = utils.GenerateSelfSignedSslCert(spicecert_file)
# Self-signed certificate -> the public certificate is also the CA public
# certificate
logging.debug("Writing the public certificate to %s",
spicecert_file)
utils.io.WriteFile(spicecacert_file, mode=0400, data=cert_pem)
# Cluster domain secret
if cds:
logging.debug("Writing cluster domain secret to %s", cds_file)
......@@ -166,7 +206,7 @@ def _InitGanetiServerSetup(master_name):
"""
# Generate cluster secrets
GenerateClusterCrypto(True, False, False, False)
GenerateClusterCrypto(True, False, False, False, False)
result = utils.RunCmd([constants.DAEMON_UTIL, "start", constants.NODED])
if result.failed:
......@@ -557,6 +597,8 @@ def SetupNodeDaemon(cluster_name, node, ssh_key_check):
# either by being constants or by the checks above
sshrunner.CopyFileToNode(node, constants.NODED_CERT_FILE)
sshrunner.CopyFileToNode(node, constants.RAPI_CERT_FILE)
sshrunner.CopyFileToNode(node, constants.SPICE_CERT_FILE)
sshrunner.CopyFileToNode(node, constants.SPICE_CACERT_FILE)
sshrunner.CopyFileToNode(node, constants.CONFD_HMAC_KEY)
mycommand = ("%s stop-all; %s start %s -b %s" %
(constants.DAEMON_UTIL, constants.DAEMON_UTIL, constants.NODED,
......
......@@ -109,6 +109,7 @@ __all__ = [
"NEW_CONFD_HMAC_KEY_OPT",
"NEW_RAPI_CERT_OPT",
"NEW_SECONDARY_OPT",
"NEW_SPICE_CERT_OPT",
"NIC_PARAMS_OPT",
"NODE_FORCE_JOIN_OPT",
"NODE_LIST_OPT",
......@@ -159,6 +160,8 @@ __all__ = [
"SHOWCMD_OPT",
"SHUTDOWN_TIMEOUT_OPT",
"SINGLE_NODE_OPT",
"SPICE_CACERT_OPT",
"SPICE_CERT_OPT",
"SRC_DIR_OPT",
"SRC_NODE_OPT",
"SUBMIT_OPT",
......@@ -1083,6 +1086,21 @@ NEW_RAPI_CERT_OPT = cli_option("--new-rapi-certificate", dest="new_rapi_cert",
help=("Generate a new self-signed RAPI"
" certificate"))
SPICE_CERT_OPT = cli_option("--spice-certificate", dest="spice_cert",
default=None,
help="File containing new SPICE certificate")
SPICE_CACERT_OPT = cli_option("--spice-ca-certificate", dest="spice_cacert",
default=None,
help="File containing the certificate of the CA"
" which signed the SPICE certificate")
NEW_SPICE_CERT_OPT = cli_option("--new-spice-certificate",
dest="new_spice_cert", default=None,
action="store_true",
help=("Generate a new self-signed SPICE"
" certificate"))
NEW_CONFD_HMAC_KEY_OPT = cli_option("--new-confd-hmac-key",
dest="new_confd_hmac_key",
default=False, action="store_true",
......
......@@ -646,9 +646,45 @@ def SearchTags(opts, args):
ToStdout("%s %s", path, tag)
def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
new_confd_hmac_key, new_cds, cds_filename,
force):
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
"""Reads and verifies an X509 certificate.
@type cert_filename: string
@param cert_filename: the path of the file containing the certificate to
verify encoded in PEM format
@type verify_private_key: bool
@param verify_private_key: whether to verify the private key in addition to
the public certificate
@rtype: string
@return: a string containing the PEM-encoded certificate.
"""
try:
pem = utils.ReadFile(cert_filename)
except IOError, err:
raise errors.X509CertError(cert_filename,
"Unable to read certificate: %s" % str(err))
try:
OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
except Exception, err:
raise errors.X509CertError(cert_filename,
"Unable to load certificate: %s" % str(err))
if verify_private_key:
try:
OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, pem)
except Exception, err:
raise errors.X509CertError(cert_filename,
"Unable to load private key: %s" % str(err))
return pem
def _RenewCrypto(new_cluster_cert, new_rapi_cert, #pylint: disable=R0911
rapi_cert_filename, new_spice_cert, spice_cert_filename,
spice_cacert_filename, new_confd_hmac_key, new_cds,
cds_filename, force):
"""Renews cluster certificates, keys and secrets.
@type new_cluster_cert: bool
......@@ -657,6 +693,13 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
@param new_rapi_cert: Whether to generate a new RAPI certificate
@type rapi_cert_filename: string
@param rapi_cert_filename: Path to file containing new RAPI certificate
@type new_spice_cert: bool
@param new_spice_cert: Whether to generate a new SPICE certificate
@type spice_cert_filename: string
@param spice_cert_filename: Path to file containing new SPICE certificate
@type spice_cacert_filename: string
@param spice_cacert_filename: Path to file containing the certificate of the
CA that signed the SPICE certificate
@type new_confd_hmac_key: bool
@param new_confd_hmac_key: Whether to generate a new HMAC key
@type new_cds: bool
......@@ -678,27 +721,26 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
" the same time.")
return 1
if rapi_cert_filename:
# Read and verify new certificate
try:
rapi_cert_pem = utils.ReadFile(rapi_cert_filename)
OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
rapi_cert_pem)
except Exception, err: # pylint: disable=W0703
ToStderr("Can't load new RAPI certificate from %s: %s" %
(rapi_cert_filename, str(err)))
return 1
if new_spice_cert and (spice_cert_filename or spice_cacert_filename):
ToStderr("When using --new-spice-certificate, the --spice-certificate"
" and --spice-ca-certificate must not be used.")
return 1
try:
OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, rapi_cert_pem)
except Exception, err: # pylint: disable=W0703
ToStderr("Can't load new RAPI private key from %s: %s" %
(rapi_cert_filename, str(err)))
return 1
if bool(spice_cacert_filename) ^ bool(spice_cert_filename):
ToStderr("Both --spice-certificate and --spice-ca-certificate must be"
" specified.")
return 1
else:
rapi_cert_pem = None
rapi_cert_pem, spice_cert_pem, spice_cacert_pem = (None, None, None)
try:
if rapi_cert_filename:
rapi_cert_pem = _ReadAndVerifyCert(rapi_cert_filename, True)
if spice_cert_filename:
spice_cert_pem = _ReadAndVerifyCert(spice_cert_filename, True)
spice_cacert_pem = _ReadAndVerifyCert(spice_cacert_filename)
except errors.X509CertError, err:
ToStderr("Unable to load X509 certificate from %s: %s", err[0], err[1])
return 1
if cds_filename:
try:
......@@ -718,10 +760,14 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
def _RenewCryptoInner(ctx):
ctx.feedback_fn("Updating certificates and keys")
bootstrap.GenerateClusterCrypto(new_cluster_cert, new_rapi_cert,
bootstrap.GenerateClusterCrypto(new_cluster_cert,
new_rapi_cert,
new_spice_cert,
new_confd_hmac_key,
new_cds,
rapi_cert_pem=rapi_cert_pem,
spice_cert_pem=spice_cert_pem,
spice_cacert_pem=spice_cacert_pem,
cds=cds)
files_to_copy = []
......@@ -732,6 +778,10 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
if new_rapi_cert or rapi_cert_pem:
files_to_copy.append(constants.RAPI_CERT_FILE)
if new_spice_cert or spice_cert_pem:
files_to_copy.append(constants.SPICE_CERT_FILE)
files_to_copy.append(constants.SPICE_CACERT_FILE)
if new_confd_hmac_key:
files_to_copy.append(constants.CONFD_HMAC_KEY)
......@@ -760,6 +810,9 @@ def RenewCrypto(opts, args):
return _RenewCrypto(opts.new_cluster_cert,
opts.new_rapi_cert,
opts.rapi_cert,
opts.new_spice_cert,
opts.spice_cert,
opts.spice_cacert,
opts.new_confd_hmac_key,
opts.new_cluster_domain_secret,
opts.cluster_domain_secret,
......@@ -1348,7 +1401,8 @@ commands = {
RenewCrypto, ARGS_NONE,
[NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT],
NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT,
NEW_SPICE_CERT_OPT, SPICE_CERT_OPT, SPICE_CACERT_OPT],
"[opts...]",
"Renews cluster certificates, keys and secrets"),
"epo": (
......
......@@ -8998,8 +8998,9 @@ class LUInstanceCreate(LogicalUnit):
feedback_fn("* running the instance OS create scripts...")
# FIXME: pass debug option from opcode to backend
result = self.rpc.call_instance_os_add(pnode_name, iobj, False,
self.op.debug_level)
os_add_result = \
self.rpc.call_instance_os_add(pnode_name, iobj, False,
self.op.debug_level)
if pause_sync:
feedback_fn("* resuming disk sync")
result = self.rpc.call_blockdev_pause_resume_sync(pnode_name,
......@@ -9009,8 +9010,8 @@ class LUInstanceCreate(LogicalUnit):
logging.warn("resume-sync of instance %s for disk %d failed",
instance, idx)
result.Raise("Could not add os for instance %s"
" on node %s" % (instance, pnode_name))
os_add_result.Raise("Could not add os for instance %s"
" on node %s" % (instance, pnode_name))
elif self.op.mode == constants.INSTANCE_IMPORT:
feedback_fn("* running the instance OS import scripts...")
......
......@@ -160,6 +160,8 @@ CLUSTER_CONF_FILE = DATA_DIR + "/config.data"
NODED_CERT_FILE = DATA_DIR + "/server.pem"
RAPI_CERT_FILE = DATA_DIR + "/rapi.pem"
CONFD_HMAC_KEY = DATA_DIR + "/hmac.key"
SPICE_CERT_FILE = DATA_DIR + "/spice.pem"
SPICE_CACERT_FILE = DATA_DIR + "/spice-ca.pem"
CLUSTER_DOMAIN_SECRET_FILE = DATA_DIR + "/cluster-domain-secret"
INSTANCE_STATUS_FILE = RUN_GANETI_DIR + "/instance-status"
SSH_KNOWN_HOSTS_FILE = DATA_DIR + "/known_hosts"
......@@ -193,7 +195,12 @@ WATCHER_GROUP_INSTANCE_STATUS_FILE = DATA_DIR + "/watcher.%s.instance-status"
#: File containing Unix timestamp until which watcher should be paused
WATCHER_PAUSEFILE = DATA_DIR + "/watcher.pause"
ALL_CERT_FILES = frozenset([NODED_CERT_FILE, RAPI_CERT_FILE])
ALL_CERT_FILES = frozenset([
NODED_CERT_FILE,
RAPI_CERT_FILE,
SPICE_CERT_FILE,
SPICE_CACERT_FILE,
])
MASTER_SOCKET = SOCKET_DIR + "/ganeti-master"
......@@ -700,6 +707,9 @@ HV_KVM_SPICE_JPEG_IMG_COMPR = "spice_jpeg_wan_compression"
HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR = "spice_zlib_glz_wan_compression"
HV_KVM_SPICE_STREAMING_VIDEO_DETECTION = "spice_streaming_video"
HV_KVM_SPICE_AUDIO_COMPR = "spice_playback_compression"
HV_KVM_SPICE_USE_TLS = "spice_use_tls"
HV_KVM_SPICE_TLS_CIPHERS = "spice_tls_ciphers"
HV_KVM_SPICE_USE_VDAGENT = "spice_use_vdagent"
HV_ACPI = "acpi"
HV_PAE = "pae"
HV_USE_BOOTLOADER = "use_bootloader"
......@@ -751,6 +761,9 @@ HVS_PARAMETER_TYPES = {
HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR: VTYPE_STRING,
HV_KVM_SPICE_STREAMING_VIDEO_DETECTION: VTYPE_STRING,
HV_KVM_SPICE_AUDIO_COMPR: VTYPE_BOOL,
HV_KVM_SPICE_USE_TLS: VTYPE_BOOL,
HV_KVM_SPICE_TLS_CIPHERS: VTYPE_STRING,
HV_KVM_SPICE_USE_VDAGENT: VTYPE_BOOL,
HV_ACPI: VTYPE_BOOL,
HV_PAE: VTYPE_BOOL,
HV_USE_BOOTLOADER: VTYPE_BOOL,
......@@ -1378,6 +1391,9 @@ HVC_DEFAULTS = {
HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR: "",
HV_KVM_SPICE_STREAMING_VIDEO_DETECTION: "",
HV_KVM_SPICE_AUDIO_COMPR: True,
HV_KVM_SPICE_USE_TLS: False,
HV_KVM_SPICE_TLS_CIPHERS: OPENSSL_CIPHERS,
HV_KVM_SPICE_USE_VDAGENT: True,
HV_KVM_FLOPPY_IMAGE_PATH: "",
HV_CDROM_IMAGE_PATH: "",
HV_KVM_CDROM2_IMAGE_PATH: "",
......
......@@ -277,6 +277,14 @@ class SshKeyError(GenericError):
"""
class X509CertError(GenericError):
"""Invalid X509 certificate.
This error has two arguments: the certificate filename and the error cause.
"""
class TagError(GenericError):
"""Generic tag error.
......
......@@ -437,6 +437,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
hv_base.ParamInSet(False,
constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
......@@ -916,7 +919,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
"""Generate KVM information to start an instance.
"""
# pylint: disable=R0914
# pylint: disable=R0914,R0915
_, v_major, v_min, _ = self._GetKVMVersion()
pidfile = self._InstancePidFile(instance.name)
......@@ -1154,7 +1157,18 @@ class KVMHypervisor(hv_base.BaseHypervisor):
# ValidateParameters checked it.
spice_address = spice_bind
spice_arg = "addr=%s,port=%s" % (spice_address, instance.network_port)
spice_arg = "addr=%s" % spice_address
if hvp[constants.HV_KVM_SPICE_USE_TLS]:
spice_arg = "%s,tls-port=%s,x509-cacert-file=%s" % (spice_arg,
instance.network_port, constants.SPICE_CACERT_FILE)
spice_arg = "%s,x509-key-file=%s,x509-cert-file=%s" % (spice_arg,
constants.SPICE_CERT_FILE, constants.SPICE_CERT_FILE)
tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
if tls_ciphers:
spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
else:
spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
spice_arg = "%s,disable-ticketing" % spice_arg
......@@ -1180,6 +1194,8 @@ class KVMHypervisor(hv_base.BaseHypervisor):
# Audio compression, by default in qemu-kvm it is on
if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
spice_arg = "%s,playback-compression=off" % spice_arg
if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
spice_arg = "%s,agent-mouse=off" % spice_arg
logging.info("KVM: SPICE will listen on port %s", instance.network_port)
kvm_cmd.extend(["-spice", spice_arg])
......@@ -1794,6 +1810,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
constants.HV_KVM_SPICE_USE_TLS,
])
for param in spice_additional_params:
if hvparams[param]:
......
......@@ -209,6 +209,10 @@ def GetPaths():
getent.masterd_gid, False),
(constants.RAPI_CERT_FILE, FILE, 0440, getent.rapi_uid,
getent.masterd_gid, False),
(constants.SPICE_CERT_FILE, FILE, 0440, getent.noded_uid,
getent.masterd_gid, False),
(constants.SPICE_CACERT_FILE, FILE, 0440, getent.noded_uid,
getent.masterd_gid, False),
(constants.NODED_CERT_FILE, FILE, 0440, getent.masterd_uid,
getent.masterd_gid, False),
]
......
......@@ -259,6 +259,8 @@ def GenerateSelfSignedX509Cert(common_name, validity):
@param common_name: commonName value
@type validity: int
@param validity: Validity for certificate in seconds
@return: a tuple of strings containing the PEM-encoded private key and
certificate
"""
# Create private and public key
......@@ -292,6 +294,8 @@ def GenerateSelfSignedSslCert(filename, common_name=constants.X509_CERT_CN,
@param common_name: commonName value
@type validity: int
@param validity: validity of certificate in number of days
@return: a tuple of strings containing the PEM-encoded private key and
certificate
"""
# TODO: Investigate using the cluster name instead of X505_CERT_CN for
......@@ -301,3 +305,4 @@ def GenerateSelfSignedSslCert(filename, common_name=constants.X509_CERT_CN,
validity * 24 * 60 * 60)
utils_io.WriteFile(filename, mode=0400, data=key_pem + cert_pem)
return (key_pem, cert_pem)
......@@ -520,6 +520,8 @@ RENEW-CRYPTO
| **renew-crypto** [-f]
| [--new-cluster-certificate] [--new-confd-hmac-key]
| [--new-rapi-certificate] [--rapi-certificate *rapi-cert*]
| [--new-spice-certificate | --spice-certificate *spice-cert*
| -- spice-ca-certificate *spice-ca-cert*]
| [--new-cluster-domain-secret] [--cluster-domain-secret *filename*]
This command will stop all Ganeti daemons in the cluster and start
......@@ -533,6 +535,12 @@ ganeti-rapi(8)) specify ``--new-rapi-certificate``. If you want to
use your own certificate, e.g. one signed by a certificate
authority (CA), pass its filename to ``--rapi-certificate``.
To generate a new self-signed SPICE certificate, used by SPICE
connections to the KVM hypervisor, specify the
``--new-spice-certificate`` option. If you want to provide a
certificate, pass its filename to ``--spice-certificate`` and pass the
signing CA certificate to ``--spice-ca-certificate``.
``--new-cluster-domain-secret`` generates a new, random cluster
domain secret. ``--cluster-domain-secret`` reads the secret from a
file. The cluster domain secret is used to sign information
......
......@@ -353,6 +353,23 @@ spice\_playback\_compression
Configures whether SPICE should compress audio streams or not.
spice\_use\_tls
Valid for the KVM hypervisor.
Specifies that the SPICE server must use TLS to encrypt all the
traffic with the client.
spice\_tls\_ciphers
Valid for the KVM hypervisor.
Specifies a list of comma-separated ciphers that SPICE should use
for TLS connections. For the format, see man cipher(1).
spice\_use\_vdagent
Valid for the KVM hypervisor.
Enables or disables passing mouse events via SPICE vdagent.
acpi
Valid for the Xen HVM and KVM hypervisors.
......
......@@ -122,6 +122,8 @@ def main():
options.SERVER_PEM_PATH = options.data_dir + "/server.pem"
options.KNOWN_HOSTS_PATH = options.data_dir + "/known_hosts"
options.RAPI_CERT_FILE = options.data_dir + "/rapi.pem"
options.SPICE_CERT_FILE = options.data_dir + "/spice.pem"
options.SPICE_CACERT_FILE = options.data_dir + "/spice-ca.pem"
options.RAPI_USERS_FILE = options.data_dir + "/rapi/users"
options.RAPI_USERS_FILE_PRE24 = options.data_dir + "/rapi_users"
options.CONFD_HMAC_KEY = options.data_dir + "/hmac.key"
......@@ -222,11 +224,13 @@ def main():
backup=True)
if not options.dry_run:
bootstrap.GenerateClusterCrypto(False, False, False, False,
nodecert_file=options.SERVER_PEM_PATH,
rapicert_file=options.RAPI_CERT_FILE,
hmackey_file=options.CONFD_HMAC_KEY,
cds_file=options.CDS_FILE)
bootstrap.GenerateClusterCrypto(False, False, False, False, False,
nodecert_file=options.SERVER_PEM_PATH,
rapicert_file=options.RAPI_CERT_FILE,
spicecert_file=options.SPICE_CERT_FILE,
spicecacert_file=options.SPICE_CACERT_FILE,
hmackey_file=options.CONFD_HMAC_KEY,
cds_file=options.CDS_FILE)
except Exception:
logging.critical("Writing configuration failed. It is probably in an"
......
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