From 8b2d10133fb93bf7049ee4a1fa7e7a8d3794cae2 Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Thu, 5 Feb 2009 13:37:00 +0000
Subject: [PATCH] KVM: add VNC TLS and X509 parameters

With this parameters VNC for KVM is able to be protected by tls,
optionally with an x509 certificate, and optionally verifying the
client as well. Additionally in this patch we limit the bind address to
being a directory, rather than a file or a directory, for simplicity, as
it allows for the same level of control anyway.

Reviewed-by: iustinp
---
 lib/constants.py         |  9 ++++++++
 lib/hypervisor/hv_kvm.py | 46 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/lib/constants.py b/lib/constants.py
index 367b31c96..ec9bd6681 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -283,6 +283,9 @@ HV_CDROM_IMAGE_PATH = "cdrom_image_path"
 HV_NIC_TYPE = "nic_type"
 HV_DISK_TYPE = "disk_type"
 HV_VNC_BIND_ADDRESS = "vnc_bind_address"
+HV_VNC_TLS = "vnc_tls"
+HV_VNC_X509 = "vnc_x509_path"
+HV_VNC_X509_VERIFY = "vnc_x509_verify"
 HV_ACPI = "acpi"
 HV_PAE = "pae"
 HV_KERNEL_PATH = "kernel_path"
@@ -296,6 +299,9 @@ HVS_PARAMETERS = frozenset([
   HV_NIC_TYPE,
   HV_DISK_TYPE,
   HV_VNC_BIND_ADDRESS,
+  HV_VNC_TLS,
+  HV_VNC_X509,
+  HV_VNC_X509_VERIFY,
   HV_ACPI,
   HV_PAE,
   HV_KERNEL_PATH,
@@ -451,6 +457,9 @@ HVC_DEFAULTS = {
     HV_ACPI: True,
     HV_SERIAL_CONSOLE: True,
     HV_VNC_BIND_ADDRESS: None,
+    HV_VNC_TLS: False,
+    HV_VNC_X509: '',
+    HV_VNC_X509_VERIFY: False,
     },
   HT_FAKE: {
     },
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index 19d96453c..0a4492503 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -55,6 +55,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     constants.HV_ACPI,
     constants.HV_SERIAL_CONSOLE,
     constants.HV_VNC_BIND_ADDRESS,
+    constants.HV_VNC_TLS,
+    constants.HV_VNC_X509,
+    constants.HV_VNC_X509_VERIFY,
     ]
 
   _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
@@ -277,11 +280,23 @@ class KVMHypervisor(hv_base.BaseHypervisor):
                         (instance.network_port,
                          constants.HT_HVM_VNC_BASE_PORT))
           vnc_arg = 'none'
+
+        # Only allow tls and other option when not binding to a file, for now.
+        # kvm/qemu gets confused otherwise about the filename to use.
+        vnc_append = ''
+        if instance.hvparams[constants.HV_VNC_TLS]:
+          vnc_append = '%s,tls' % vnc_append
+          if instance.hvparams[constants.HV_VNC_X509_VERIFY]:
+            vnc_append = '%s,x509verify=%s' % (vnc_append,
+              instance.hvparams[constants.HV_VNC_X509])
+          elif instance.hvparams[constants.HV_VNC_X509]:
+            vnc_append = '%s,x509=%s' % (vnc_append,
+              instance.hvparams[constants.HV_VNC_X509])
+        vnc_arg = '%s%s' % (vnc_arg, vnc_append)
+
       else:
-        if os.path.isdir(vnc_bind_address):
-          vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
-        else:
-          vnc_arg = 'unix:%s' % vnc_bind_address
+        vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
+
       kvm_cmd.extend(['-vnc', vnc_arg])
     else:
       kvm_cmd.extend(['-nographic'])
@@ -696,6 +711,17 @@ class KVMHypervisor(hv_base.BaseHypervisor):
                                        " pathname. '%s' given" %
                                        vnc_bind_address)
 
+    if hvparams[constants.HV_VNC_X509_VERIFY] and \
+      not hvparams[constants.HV_VNC_X509]:
+        raise errors.HypervisorError("%s must be defined, if %s is" %
+                                     (constants.HV_VNC_X509,
+                                      constants.HV_VNC_X509_VERIFY))
+
+    if hvparams[constants.HV_VNC_X509]:
+      if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
+        raise errors.HypervisorError("The vnc x509 path must an absolute path"
+                                     ", if defined")
+
   def ValidateParameters(self, hvparams):
     """Check the given parameters for validity.
 
@@ -713,3 +739,15 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     if initrd_path and not os.path.isfile(initrd_path):
       raise errors.HypervisorError("Instance initrd '%s' not found or"
                                    " not a file" % initrd_path)
+
+    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
+    if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
+       not os.path.isdir(vnc_bind_address):
+       raise errors.HypervisorError("Instance vnc bind address must be either"
+                                    " an ip address or an existing directory")
+
+    vnc_x509 = hvparams[constants.HV_VNC_X509]
+    if vnc_x509 and not os.path.isdir(vnc_x509):
+      raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
+                                   " or not a directory" % vnc_x509)
+
-- 
GitLab