Added an optional parameter called spice_password_file that allows the user to protect the SPICE login with the password contained in the specified file.
Signed-off-by: Andrea Spadaccini <[email protected]> --- lib/constants.py | 3 ++ lib/hypervisor/hv_kvm.py | 47 +++++++++++++++++++++++++++++++++++++++++++-- man/gnt-instance.rst | 7 ++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/lib/constants.py b/lib/constants.py index 3cc6cb6..d945542 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -666,6 +666,7 @@ HV_VNC_X509 = "vnc_x509_path" HV_VNC_X509_VERIFY = "vnc_x509_verify" HV_KVM_SPICE_BIND = "spice_bind" HV_KVM_SPICE_IP_VERSION = "spice_ip_version" +HV_KVM_SPICE_PASSWORD_FILE = "spice_password_file" HV_ACPI = "acpi" HV_PAE = "pae" HV_USE_BOOTLOADER = "use_bootloader" @@ -711,6 +712,7 @@ HVS_PARAMETER_TYPES = { HV_VNC_X509_VERIFY: VTYPE_BOOL, HV_KVM_SPICE_BIND: VTYPE_STRING, HV_KVM_SPICE_IP_VERSION: VTYPE_INT, + HV_KVM_SPICE_PASSWORD_FILE: VTYPE_STRING, HV_ACPI: VTYPE_BOOL, HV_PAE: VTYPE_BOOL, HV_USE_BOOTLOADER: VTYPE_BOOL, @@ -1291,6 +1293,7 @@ HVC_DEFAULTS = { HV_VNC_PASSWORD_FILE: "", HV_KVM_SPICE_BIND: "", HV_KVM_SPICE_IP_VERSION: IFACE_NO_IP_VERSION_SPECIFIED, + HV_KVM_SPICE_PASSWORD_FILE: "", HV_KVM_FLOPPY_IMAGE_PATH: "", HV_CDROM_IMAGE_PATH: "", HV_KVM_CDROM2_IMAGE_PATH: "", diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py index 622df48..14cb945 100644 --- a/lib/hypervisor/hv_kvm.py +++ b/lib/hypervisor/hv_kvm.py @@ -352,6 +352,7 @@ class KVMHypervisor(hv_base.BaseHypervisor): x in constants.VALID_IP_VERSIONS), "the SPICE IP version should be 4 or 6", None, None), + constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_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, @@ -949,8 +950,10 @@ class KVMHypervisor(hv_base.BaseHypervisor): # ValidateParameters checked it. spice_address = spice_bind - spice_arg = "addr=%s,port=%s,disable-ticketing" % (spice_address, - instance.network_port) + spice_arg = "addr=%s,port=%s" % (spice_address, instance.network_port) + if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]: + spice_arg = "%s,disable-ticketing" % spice_arg + if spice_ip_version: spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version) @@ -1128,6 +1131,12 @@ class KVMHypervisor(hv_base.BaseHypervisor): utils.EnsureDirs([(self._InstanceChrootDir(name), constants.SECURE_DIR_MODE)]) + # Automatically enable QMP if version is >= 0.14 + if (v_major, v_min) >= (0, 14): + logging.debug("Enabling QMP") + kvm_cmd.extend(["-qmp", "unix:%s,server,nowait"% + self._InstanceQmpMonitor(instance.name)]) + # Configure the network now for starting instances and bridged interfaces, # during FinalizeMigration for incoming instances' routed interfaces for nic_seq, nic in enumerate(kvm_nics): @@ -1164,6 +1173,26 @@ class KVMHypervisor(hv_base.BaseHypervisor): change_cmd = "change vnc password %s" % vnc_pwd self._CallMonitorCommand(instance.name, change_cmd) + # Setting SPICE password. We are not vulnerable to malicious passwordless + # connection attempts because SPICE by default does not allow connections + # if neither a password nor the "disable_ticketing" options are specified. + # As soon as we send the password via QMP, that password is a valid ticket + # for connection. + spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE] + if spice_password_file: + try: + spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True) + qmp = QmpConnection(self._InstanceQmpMonitor(instance.name)) + qmp.connect() + arguments = { + "protocol": "spice", + "password": spice_pwd, + } + qmp.Execute("set_password", arguments) + except EnvironmentError, err: + raise errors.HypervisorError("Failed to open SPICE password file %s: %s" + % (spice_password_file, err)) + for filename in temp_files: utils.RemoveFile(filename) @@ -1486,8 +1515,9 @@ class KVMHypervisor(hv_base.BaseHypervisor): " security model is 'none' or 'pool'") spice_bind = hvparams[constants.HV_KVM_SPICE_BIND] + spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION] + spice_password_file = hvparams[constants.HV_KVM_SPICE_PASSWORD_FILE] if spice_bind: - spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION] if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED: # if an IP version is specified, the spice_bind parameter must be an # IP of that family @@ -1502,6 +1532,17 @@ class KVMHypervisor(hv_base.BaseHypervisor): raise errors.HypervisorError("spice: got an IPv6 address (%s), but" " the specified IP version is %s" % (spice_bind, spice_ip_version)) + else: + if spice_ip_version: + raise errors.HypervisorError("spice: the %s option is useless" + " without %s" % + (constants.HV_KVM_SPICE_IP_VERSION, + constants.HV_KVM_SPICE_BIND)) + if spice_password_file: + raise errors.HypervisorError("spice: the %s option is useless" + " without %s" % + (constants.HV_KVM_SPICE_PASSWORD_FILE, + constants.HV_KVM_SPICE_BIND)) @classmethod def ValidateParameters(cls, hvparams): diff --git a/man/gnt-instance.rst b/man/gnt-instance.rst index 5d906a4..c3a0c92 100644 --- a/man/gnt-instance.rst +++ b/man/gnt-instance.rst @@ -300,6 +300,13 @@ spice\_ip\_version this case, if the ``spice_ip_version`` parameter is not used, the default IP version of the cluster will be used. +spice\_password\_file + Valid for the KVM hypervisor. + + Specifies a file containing the password that must be used when + connecting via the SPICE protocol. If the option is not specified, + passwordless connections are allowed. + acpi Valid for the Xen HVM and KVM hypervisors. -- 1.7.3.1
