Implemented usage libvirt+tls

Enable TLS transport.

compute:
  libvirt:
    tls:
      enabled: True

You able to set custom certificates in pillar:

  nova:
    compute:
      libvirt:
        tls:
          key: (certificate content)
          cert: (certificate content)
          cacert: (certificate content)
          client:
            key: (certificate content)
            cert: (certificate content)

Related-Prod: PROD-19149

Change-Id: Iea4c44703e837693b218648c0090b35c129daa5f
diff --git a/README.rst b/README.rst
index c5606e8..6d9c848 100644
--- a/README.rst
+++ b/README.rst
@@ -920,6 +920,33 @@
 You can read more about injecting the administrator password here:
     https://docs.openstack.org/nova/queens/admin/admin-password-injection.html
 
+Enable libvirt control channel over TLS
+---------------------
+
+By default TLS is disabled.
+
+Enable TLS transport.
+
+  compute:
+    libvirt:
+      tls:
+        enabled: True
+
+You able to set custom certificates in pillar:
+
+  nova:
+    compute:
+      libvirt:
+        tls:
+          key: (certificate content)
+          cert: (certificate content)
+          cacert: (certificate content)
+          client:
+            key: (certificate content)
+            cert: (certificate content)
+
+You can read more about live migration over TLS here:
+    https://wiki.libvirt.org/page/TLSCreateServerCerts
 
 Documentation and Bugs
 ======================
diff --git a/nova/compute.sls b/nova/compute.sls
index 33d30de..5a13581 100644
--- a/nova/compute.sls
+++ b/nova/compute.sls
@@ -138,6 +138,74 @@
 {%- endif %}
 {%- endif %}
 
+{%- if compute.libvirt.get('tls',{}).get('enabled',False)  %}
+{%- set ca_file=compute.libvirt.tls.get('ca_file') %}
+{%- set key_file=compute.libvirt.tls.get('key_file') %}
+{%- set cert_file=compute.libvirt.tls.get('cert_file') %}
+{%- set client_key_file=compute.libvirt.tls.client.get('key_file') %}
+{%- set client_cert_file=compute.libvirt.tls.client.get('cert_file') %}
+
+libvirt_ca_nova_compute:
+{%- if compute.libvirt.tls.cacert is defined %}
+  file.managed:
+    - name: {{ ca_file }}
+    - contents_pillar: nova:compute:libvirt:tls:cacert
+    - mode: 444
+    - makedirs: true
+{%- else %}
+  file.exists:
+   - name: {{ ca_file }}
+{%- endif %}
+
+libvirt_public_cert:
+{%- if compute.libvirt.tls.cert is defined %}
+  file.managed:
+    - name: {{ cert_file }}
+    - contents_pillar: nova:compute:libvirt:tls:cert
+    - mode: 440
+    - makedirs: true
+{%- else %}
+  file.exists:
+   - name: {{ cert_file }}
+{%- endif %}
+
+libvirt_private_key:
+{%- if compute.libvirt.tls.key is defined %}
+  file.managed:
+    - name: {{ key_file }}
+    - contents_pillar: nova:compute:libvirt:tls:key
+    - mode: 400
+    - makedirs: true
+{%- else %}
+  file.exists:
+   - name: {{ key_file }}
+{%- endif %}
+
+libvirt_client_public_cert:
+{%- if compute.libvirt.tls.client.cert is defined %}
+  file.managed:
+    - name: {{ client_cert_file }}
+    - contents_pillar: nova:compute:libvirt:tls:client:cert
+    - mode: 440
+    - makedirs: true
+{%- else %}
+  file.exists:
+   - name: {{ client_cert_file }}
+{%- endif %}
+
+libvirt_client_key:
+{%- if compute.libvirt.tls.client.key is defined %}
+  file.managed:
+    - name: {{ client_key_file }}
+    - contents_pillar: nova:compute:libvirt:tls:client:key
+    - mode: 400
+    - makedirs: true
+{%- else %}
+  file.exists:
+   - name: {{ client_key_file }}
+{%- endif %}
+{%- endif %}
+
 nova_compute_services:
   service.running:
   - enable: true
diff --git a/nova/files/pike/libvirtd.conf.Debian b/nova/files/pike/libvirtd.conf.Debian
index 6f4afb9..0f6b341 100644
--- a/nova/files/pike/libvirtd.conf.Debian
+++ b/nova/files/pike/libvirtd.conf.Debian
@@ -22,11 +22,17 @@
 # This is enabled by default, uncomment this to disable it
 #listen_tls = 0
 
-
+{%- if compute.libvirt.tls.get('enabled', False) %}
+listen_tcp = 0
+listen_tls = 1
+key_file = {{compute.libvirt.tls.key_file|yaml_squote}}
+cert_file = {{compute.libvirt.tls.cert_file|yaml_squote}}
+ca_file = {{compute.libvirt.tls.ca_file|yaml_squote}}
+{% else %}
 listen_tls = 0
 listen_tcp = 1
 auth_tcp = "none"
-
+{% endif %}
 
 # Listen for unencrypted TCP connections on the public TCP/IP port.
 # NB, must pass the --listen flag to the libvirtd process for this to
diff --git a/nova/files/pike/nova-compute.conf.Debian b/nova/files/pike/nova-compute.conf.Debian
index e604d72..5427ce6 100644
--- a/nova/files/pike/nova-compute.conf.Debian
+++ b/nova/files/pike/nova-compute.conf.Debian
@@ -6009,10 +6009,14 @@
 {%- endif %}
 {%- endif %}
 
+{%- if compute.libvirt.tls.get('enabled', False) %}
+live_migration_scheme="tls"
+{%- else %}
 {%- if compute.get('libvirt', {}).uri is defined %}
 connection_uri={{ compute.libvirt.uri }}
 {%- endif %}
-#
+{%- endif %}
+
 # The ID of the image to boot from to rescue data from a corrupted instance.
 #
 # If the rescue REST API operation doesn't provide an ID of an image to
diff --git a/nova/files/queens/libvirtd.conf.Debian b/nova/files/queens/libvirtd.conf.Debian
index 6f4afb9..0f6b341 100644
--- a/nova/files/queens/libvirtd.conf.Debian
+++ b/nova/files/queens/libvirtd.conf.Debian
@@ -22,11 +22,17 @@
 # This is enabled by default, uncomment this to disable it
 #listen_tls = 0
 
-
+{%- if compute.libvirt.tls.get('enabled', False) %}
+listen_tcp = 0
+listen_tls = 1
+key_file = {{compute.libvirt.tls.key_file|yaml_squote}}
+cert_file = {{compute.libvirt.tls.cert_file|yaml_squote}}
+ca_file = {{compute.libvirt.tls.ca_file|yaml_squote}}
+{% else %}
 listen_tls = 0
 listen_tcp = 1
 auth_tcp = "none"
-
+{% endif %}
 
 # Listen for unencrypted TCP connections on the public TCP/IP port.
 # NB, must pass the --listen flag to the libvirtd process for this to
diff --git a/nova/files/queens/nova-compute.conf.Debian b/nova/files/queens/nova-compute.conf.Debian
index ae43c20..62ece42 100644
--- a/nova/files/queens/nova-compute.conf.Debian
+++ b/nova/files/queens/nova-compute.conf.Debian
@@ -6393,9 +6393,13 @@
 {%- endif %}
 {%- endif %}
 
+{%- if compute.libvirt.tls.get('enabled', False) %}
+live_migration_scheme="tls"
+{%- else %}
 {%- if compute.get('libvirt', {}).uri is defined %}
 connection_uri={{ compute.libvirt.uri }}
 {%- endif %}
+{%- endif %}
 
 #
 # The ID of the image to boot from to rescue data from a corrupted
diff --git a/nova/map.jinja b/nova/map.jinja
index e9282b7..8c9eb96 100644
--- a/nova/map.jinja
+++ b/nova/map.jinja
@@ -127,6 +127,14 @@
   libvirt:
     inject_partition: '-2'
     inject_password: False
+    tls:
+      enabled: False
+      key_file: '/etc/pki/libvirt/private/serverkey.pem'
+      cert_file: '/etc/pki/libvirt/servercert.pem'
+      ca_file: '/etc/pki/CA/cacert.pem'
+      client:
+        key_file: '/etc/pki/libvirt/private/clientkey.pem'
+        cert_file: '/etc/pki/libvirt/clientcert.pem'
   instances_path: "$state_path/instances"
   notification: false
   availability_zone:
@@ -163,6 +171,14 @@
   libvirt:
     inject_partition: '-2'
     inject_password: False
+    tls:
+      enabled: False
+      key_file: '/etc/pki/libvirt/private/serverkey.pem'
+      cert_file: '/etc/pki/libvirt/servercert.pem'
+      ca_file: '/etc/pki/CA/cacert.pem'
+      client:
+        key_file: '/etc/pki/libvirt/private/clientkey.pem'
+        cert_file: '/etc/pki/libvirt/clientcert.pem'
   notification: false
   availability_zone:
   identity: