diff --git a/ansible/roles/nova/defaults/main.yml b/ansible/roles/nova/defaults/main.yml
index dab5ad4453..282f0cf380 100644
--- a/ansible/roles/nova/defaults/main.yml
+++ b/ansible/roles/nova/defaults/main.yml
@@ -362,7 +362,7 @@ nova_compute_host_rp_filter_mode: 0
 nova_enable_rolling_upgrade: "yes"
 nova_safety_upgrade: "no"
 
-nova_libvirt_port: "16509"
+nova_libvirt_port: "{{'16514' if libvirt_tls | bool  else '16509'}}"
 nova_ssh_port: "8022"
 
 nova_services_require_nova_conf:
@@ -435,6 +435,17 @@ ovs_bridge: "nsx-managed"
 qemu_max_files: 32768
 # The number of max processes qemu can open
 qemu_max_processes: 131072
+# Use TLS for libvirt connections and live migration
+libvirt_tls: false
+# Should kolla-ansible manage/copy the certs.  False, assumes the deployer is
+# responsible for making the TLS certs show up in the config directories
+# also means the deployer is responsible for restarting the nova_compute and
+# nova_libvirt containers when the key changes, as we can't know when to do that
+libvirt_tls_manage_certs: true
+# When using tls we are verfiying the hostname we are connected to matches the
+# libvirt cert we are presented.  As such we can't use IP's here, but keep the
+# ability for people to override the hostname to use.
+migration_hostname: "{{ ansible_nodename }}"
 
 ####################
 # Kolla
diff --git a/ansible/roles/nova/tasks/config-libvirt-tls.yml b/ansible/roles/nova/tasks/config-libvirt-tls.yml
new file mode 100644
index 0000000000..1868c3f659
--- /dev/null
+++ b/ansible/roles/nova/tasks/config-libvirt-tls.yml
@@ -0,0 +1,14 @@
+---
+- name: Copying over libvirt TLS keys {{ file }}
+  become: true
+  copy:
+    src: "{{ first_found }}"
+    dest: "{{ node_config_directory }}/{{ service_name }}/{{ file }}"
+    mode: "0600"
+  with_first_found:
+    - "{{ node_custom_config }}/nova/nova-libvirt/{{ inventory_hostname }}/{{ file }}"
+    - "{{ node_custom_config }}/nova/nova-libvirt/{{ file }}"
+  loop_control:
+    loop_var: first_found
+  notify:
+    - Restart {{ service_name }} container
diff --git a/ansible/roles/nova/tasks/config.yml b/ansible/roles/nova/tasks/config.yml
index 043bf4bc77..9e126cbd18 100644
--- a/ansible/roles/nova/tasks/config.yml
+++ b/ansible/roles/nova/tasks/config.yml
@@ -114,6 +114,40 @@
   notify:
     - Restart nova-libvirt container
 
+- name: Copying over libvirt TLS keys (nova-libvirt)
+  include_tasks: "config-libvirt-tls.yml"
+  vars:
+    service: "{{ nova_services['nova-libvirt'] }}"
+    service_name: nova-libvirt
+    file: "{{ item }}"
+  when:
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - libvirt_tls | bool
+    - libvirt_tls_manage_certs | bool
+  with_items:
+    - cacert.pem
+    - servercert.pem
+    - serverkey.pem
+    - clientcert.pem
+    - clientkey.pem
+
+- name: Copying over libvirt TLS keys (nova-compute)
+  include_tasks: "config-libvirt-tls.yml"
+  vars:
+    service: "{{ nova_services['nova-compute'] }}"
+    service_name: nova-compute
+    file: "{{ item }}"
+  when:
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - libvirt_tls | bool
+    - libvirt_tls_manage_certs | bool
+  with_items:
+    - cacert.pem
+    - clientcert.pem
+    - clientkey.pem
+
 - name: Copying files for nova-ssh
   become: true
   vars:
diff --git a/ansible/roles/nova/templates/libvirtd.conf.j2 b/ansible/roles/nova/templates/libvirtd.conf.j2
index 4e8863f90a..e094a5b2de 100644
--- a/ansible/roles/nova/templates/libvirtd.conf.j2
+++ b/ansible/roles/nova/templates/libvirtd.conf.j2
@@ -1,8 +1,17 @@
+{% if libvirt_tls | bool %}
+listen_tls = 1
+listen_tcp = 0
+tls_port = "{{ nova_libvirt_port }}"
+key_file = "/etc/pki/libvirt/private/serverkey.pem"
+cert_file = "/etc/pki/libvirt/servercert.pem"
+ca_file = "/etc/pki/CA/cacert.pem"
+{% else %}
 listen_tcp = 1
 listen_tls = 0
 auth_tcp = "none"
+tcp_port = "{{ nova_libvirt_port }}"
 ca_file = ""
+{% endif %}
 log_level = 3
 log_outputs = "3:file:/var/log/kolla/libvirt/libvirtd.log"
 listen_addr = "{{ migration_interface_address }}"
-tcp_port = "{{ nova_libvirt_port }}"
diff --git a/ansible/roles/nova/templates/nova-compute.json.j2 b/ansible/roles/nova/templates/nova-compute.json.j2
index 61305c3794..22dd0c843f 100644
--- a/ansible/roles/nova/templates/nova-compute.json.j2
+++ b/ansible/roles/nova/templates/nova-compute.json.j2
@@ -24,6 +24,24 @@
             "dest": "/etc/nova/vmware_ca",
             "owner": "nova",
             "perm": "0600"
+        }{% endif %}{% if libvirt_tls | bool %},
+        {
+            "source": "{{ container_config_directory }}/clientkey.pem",
+            "dest": "/etc/pki/libvirt/private/clientkey.pem",
+            "owner": "root:nova",
+            "perm": "0640"
+        },
+        {
+            "source": "{{ container_config_directory }}/clientcert.pem",
+            "dest": "/etc/pki/libvirt/clientcert.pem",
+            "owner": "root:nova",
+            "perm": "0640"
+        },
+        {
+            "source": "{{ container_config_directory }}/cacert.pem",
+            "dest": "/etc/pki/CA/cacert.pem",
+            "owner": "root:nova",
+            "perm": "0640"
         }{% endif %},
         {
             "source": "{{ container_config_directory }}/release",
diff --git a/ansible/roles/nova/templates/nova-libvirt.json.j2 b/ansible/roles/nova/templates/nova-libvirt.json.j2
index 649e2f809f..79a70172b5 100644
--- a/ansible/roles/nova/templates/nova-libvirt.json.j2
+++ b/ansible/roles/nova/templates/nova-libvirt.json.j2
@@ -12,7 +12,37 @@
             "dest": "/etc/libvirt/qemu.conf",
             "owner": "root",
             "perm": "0600"
-        }{% if nova_backend == "rbd" or cinder_backend_ceph | bool %},
+        }{% if libvirt_tls | bool %},
+        {
+            "source": "{{ container_config_directory }}/serverkey.pem",
+            "dest": "/etc/pki/libvirt/private/serverkey.pem",
+            "owner": "root",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/servercert.pem",
+            "dest": "/etc/pki/libvirt/servercert.pem",
+            "owner": "root",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/clientkey.pem",
+            "dest": "/etc/pki/libvirt/private/clientkey.pem",
+            "owner": "root",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/clientcert.pem",
+            "dest": "/etc/pki/libvirt/clientcert.pem",
+            "owner": "root",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/cacert.pem",
+            "dest": "/etc/pki/CA/cacert.pem",
+            "owner": "root",
+            "perm": "0600"
+        }{% endif %}{% if nova_backend == "rbd" or cinder_backend_ceph | bool %},
         {
             "source": "{{ container_config_directory }}/secrets",
             "dest": "/etc/libvirt/secrets",
diff --git a/ansible/roles/nova/templates/nova.conf.d/libvirt.conf.j2 b/ansible/roles/nova/templates/nova.conf.d/libvirt.conf.j2
index f48c63040a..04749e44bf 100644
--- a/ansible/roles/nova/templates/nova.conf.d/libvirt.conf.j2
+++ b/ansible/roles/nova/templates/nova.conf.d/libvirt.conf.j2
@@ -1,5 +1,10 @@
 [libvirt]
+{% if libvirt_tls | bool %}
+connection_uri = "qemu+tls://{{ migration_hostname }}/system"
+live_migration_uri = "qemu+tls://%s/system"
+{% else %}
 connection_uri = "qemu+tcp://{{ migration_interface_address }}/system"
+{% endif %}
 {% if enable_ceph | bool and nova_backend == "rbd" %}
 images_type = rbd
 images_rbd_pool = {{ ceph_nova_pool_name }}
diff --git a/doc/source/reference/compute/index.rst b/doc/source/reference/compute/index.rst
index 5c0020b8c1..4be9689c07 100644
--- a/doc/source/reference/compute/index.rst
+++ b/doc/source/reference/compute/index.rst
@@ -9,6 +9,7 @@ compute services like HyperV, XenServer and so on.
    :maxdepth: 1
 
    hyperv-guide
+   libvirt-tls-guide
    masakari-guide
    nova-fake-driver
    qinling-guide
diff --git a/doc/source/reference/compute/libvirt-tls-guide.rst b/doc/source/reference/compute/libvirt-tls-guide.rst
new file mode 100644
index 0000000000..c8021df8ed
--- /dev/null
+++ b/doc/source/reference/compute/libvirt-tls-guide.rst
@@ -0,0 +1,96 @@
+.. libvirt-tls-guide:
+
+===========
+Libvirt TLS
+===========
+
+The default configuration of Kolla Ansible is to run libvirt over TCP, with
+authentication disabled. As long as one takes steps to protect who can access
+the port this works well. However, in the case where you want live-migration to
+be allowed across hypervisors one may want to either add some level of
+authentication to the connections or make sure VM data is passed between
+hypervisors in a secure manner. To do this we can enable TLS for libvirt and
+make nova use it.
+
+Using libvirt TLS
+~~~~~~~~~~~~~~~~~
+
+Libvirt TLS can be enabled in Kolla Ansible by setting the following option in
+``/etc/kolla/globals.yml``:
+
+.. code-block:: yaml
+
+   libvirt_tls: "yes"
+
+Creation of the TLS certificates is currently out-of-scope for Kolla Ansible.
+You will need to either use an existing Internal CA or you will need to
+generate your own offline CA. For the TLS communication to work correctly you
+will have to supply Kolla Ansible the following pieces of information:
+
+* cacert.pem
+
+  - This is the CA's public certificate that all of the client and server
+    certificates are signed with. Libvirt and nova-compute will need this so
+    they can verify that all the certificates being used were signed by the CA
+    and should be trusted.
+
+* serverkey.pem
+
+  - This is the private key for the server, and is no different than the
+    private key of a TLS certificate. It should be carefully protected, just
+    like the private key of a TLS certificate.
+
+* servercert.pem
+
+  - This is the public certificate for the server. Libvirt will present this
+    certificate to any connection made to the TLS port. This is no different
+    than the public certificate part of a standard TLS certificate/key bundle.
+
+* clientkey.pem
+
+  - This is the client private key, which nova-compute/libvirt will use
+    when it is connecting to libvirt. Think of this as an SSH private key
+    and protect it in a similar manner.
+
+* clientcert.pem
+
+  - This is the client certificate that nova-compute/libvirt will present when
+    it is connecting to libvirt. Think of this as the public side of an SSH
+    key.
+
+Kolla Ansible will search for these files for each compute node in the
+following locations and order on the host where Kolla Ansible is executed:
+
+- ``/etc/kolla/config/nova/nova-libvirt/<hostname>/``
+- ``/etc/kolla/config/nova/nova-libvirt/``
+
+In most cases you will want to have a unique set of server and client
+certificates and keys per hypervisor and with a common CA certificate. In this
+case you would place each of the server/client certificate and key PEM files
+under ``/etc/kolla/config/nova/nova-libvirt/<hostname>/`` and the CA
+certificate under ``/etc/kolla/config/nova/nova-libvirt/``.
+
+However, it is possible to make use of wildcard server certificate and a single
+client certificate that is shared by all servers. This will allow you to
+generate a single client certificate and a single server certificate that is
+shared across every hypervisor. In this case you would store everything under
+``/etc/kolla/config/nova/nova-libvirt/``.
+
+Externally managed certificates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One more option for deployers who already have automation to get TLS certs onto
+servers is to disable certificate management under ``/etc/kolla/globals.yaml``:
+
+.. code-block:: yaml
+
+   libvirt_tls_manage_certs: "no"
+
+With this option disabled Kolla Ansible will simply assume that certificates
+and keys are already installed in their correct locations. Deployers will be
+responsible for making sure that the TLS certificates/keys get placed in to the
+correct container configuration directories on the servers so that they can get
+copied into the nova-compute and nova-libvirt containers. With this option
+disabled you will also be responsible for restarting the nova-compute and
+nova-libvirt containers when the certs are updated, as kolla-ansible will not
+be able to tell when the files have changed.
diff --git a/releasenotes/notes/libvirt-tls-support-4ab81fbdbf5519d3.yaml b/releasenotes/notes/libvirt-tls-support-4ab81fbdbf5519d3.yaml
new file mode 100644
index 0000000000..bb765e0bea
--- /dev/null
+++ b/releasenotes/notes/libvirt-tls-support-4ab81fbdbf5519d3.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Adds support for configuring libvirt with TLS support.  This allows for
+    secure communication between nova-compute and libvirt as well as between
+    libvirt on different hypervisors, during live-migration.  The default
+    configuration passes data in plain text, over TCP, without authentication.