diff --git a/ansible/certificates.yml b/ansible/certificates.yml
index f8021fcfc3..4b6d2528d9 100644
--- a/ansible/certificates.yml
+++ b/ansible/certificates.yml
@@ -1,4 +1,7 @@
 ---
+- import_playbook: gather-facts.yml
+  when: kolla_enable_tls_backend | default(false) | bool
+
 - name: Apply role certificates
   hosts: localhost
   roles:
diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 148112835f..d31fc2e106 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -747,11 +747,18 @@ haproxy_user: "openstack"
 haproxy_enable_external_vip: "{{ 'no' if kolla_same_external_internal_vip | bool else 'yes' }}"
 kolla_enable_tls_internal: "no"
 kolla_enable_tls_external: "{{ kolla_enable_tls_internal if kolla_same_external_internal_vip | bool else 'no' }}"
-kolla_external_fqdn_cert: "{{ node_config }}/certificates/haproxy.pem"
-kolla_internal_fqdn_cert: "{{ node_config }}/certificates/haproxy-internal.pem"
-kolla_external_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy.crt"
-kolla_internal_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy-internal.crt"
+kolla_certificates_dir: "{{ node_config }}/certificates"
+kolla_external_fqdn_cert: "{{ kolla_certificates_dir }}/haproxy.pem"
+kolla_internal_fqdn_cert: "{{ kolla_certificates_dir }}/haproxy-internal.pem"
+kolla_external_fqdn_cacert: "{{ kolla_certificates_dir }}/ca/haproxy.crt"
+kolla_internal_fqdn_cacert: "{{ kolla_certificates_dir }}/ca/haproxy-internal.crt"
 kolla_copy_ca_into_containers: "no"
+kolla_verify_tls_backend: "yes"
+haproxy_backend_cacert: "{{ 'ca-certificates.crt' if kolla_base_distro in ['debian', 'ubuntu'] else 'ca-bundle.trust.crt' }}"
+haproxy_backend_cacert_dir: "/etc/ssl/certs"
+kolla_enable_tls_backend: "no"
+kolla_tls_backend_cert: "{{ kolla_certificates_dir }}/backend-cert.pem"
+kolla_tls_backend_key: "{{ kolla_certificates_dir }}/backend-key.pem"
 
 ####################
 # Kibana options
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index 483bc94491..65cc85e67a 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -35,6 +35,9 @@ compute
 [baremetal:children]
 control
 
+[tls-backend:children]
+control
+
 [grafana:children]
 monitoring
 
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index 98e4f1bb18..cbd415c3bb 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -39,6 +39,9 @@ compute
 storage
 monitoring
 
+[tls-backend:children]
+control
+
 # You can explicitly specify which hosts run each project by updating the
 # groups in the sections below. Common services are grouped together.
 [chrony-server:children]
diff --git a/ansible/roles/certificates/defaults/main.yml b/ansible/roles/certificates/defaults/main.yml
deleted file mode 100644
index a741e6a32a..0000000000
--- a/ansible/roles/certificates/defaults/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-# Directory on deploy node (localhost) in which certificates are generated.
-certificates_dir: "{{ node_config }}/certificates"
diff --git a/ansible/roles/certificates/tasks/generate.yml b/ansible/roles/certificates/tasks/generate.yml
index 6865c12393..0647bfe3e9 100644
--- a/ansible/roles/certificates/tasks/generate.yml
+++ b/ansible/roles/certificates/tasks/generate.yml
@@ -1,21 +1,33 @@
 ---
 - name: Ensuring private internal directory exist
   file:
-    path: "{{ certificates_dir }}/private/internal"
+    path: "{{ kolla_certificates_dir }}/private/internal"
     state: "directory"
     recurse: yes
     mode: "0770"
 
 - name: Ensuring private external directory exist
   file:
-    path: "{{ certificates_dir }}/private/external"
+    path: "{{ kolla_certificates_dir }}/private/external"
     state: "directory"
     recurse: yes
     mode: "0770"
 
+- name: Ensuring backend certificate and key directories exist
+  file:
+    path: "{{ item | dirname }}"
+    state: "directory"
+    recurse: yes
+    mode: "0770"
+  when:
+    - kolla_enable_tls_backend | bool
+  with_items:
+    - "{{ kolla_tls_backend_cert }}"
+    - "{{ kolla_tls_backend_key }}"
+
 - name: Ensuring ca directory exist
   file:
-    path: "{{ certificates_dir }}/ca"
+    path: "{{ kolla_certificates_dir }}/ca"
     state: "directory"
     recurse: yes
     mode: "0770"
@@ -24,36 +36,36 @@
     - name: Creating external SSL configuration file
       template:
         src: "{{ item }}.j2"
-        dest: "{{ certificates_dir }}/{{ item }}"
+        dest: "{{ kolla_certificates_dir }}/{{ item }}"
         mode: "0660"
       with_items:
         - "openssl-kolla.cnf"
     - name: Creating external Key
       command: creates="{{ item }}" openssl genrsa -out {{ item }}
       with_items:
-        - "{{ certificates_dir }}/private/external/external.key"
+        - "{{ kolla_certificates_dir }}/private/external/external.key"
     - name: Setting permissions on external key
       file:
-        path: "{{ certificates_dir }}/private/external/external.key"
+        path: "{{ kolla_certificates_dir }}/private/external/external.key"
         mode: "0660"
         state: file
     - name: Creating external Server Certificate
       command: creates="{{ item }}" openssl req -new -nodes -sha256 -x509 \
-        -config {{ certificates_dir }}/openssl-kolla.cnf \
+        -config {{ kolla_certificates_dir }}/openssl-kolla.cnf \
         -days 3650 \
         -extensions v3_req \
-        -key {{ certificates_dir }}/private/external/external.key \
+        -key {{ kolla_certificates_dir }}/private/external/external.key \
         -out {{ item }}
       with_items:
-        - "{{ certificates_dir }}/private/external/external.crt"
+        - "{{ kolla_certificates_dir }}/private/external/external.crt"
     - name: Creating external CA Certificate File
       copy:
-        src: "{{ certificates_dir }}/private/external/external.crt"
+        src: "{{ kolla_certificates_dir }}/private/external/external.crt"
         dest: "{{ kolla_external_fqdn_cacert }}"
         mode: "0660"
     - name: Creating external Server PEM File
       assemble:
-        src: "{{ certificates_dir }}/private/external"
+        src: "{{ kolla_certificates_dir }}/private/external"
         dest: "{{ kolla_external_fqdn_cert }}"
         mode: "0660"
   when:
@@ -62,14 +74,14 @@
 - block:
     - name: Copy the external certificate crt to be the internal when internal + external are same network
       copy:
-        src: "{{ certificates_dir }}/private/external/external.crt"
-        dest: "{{ certificates_dir }}/private/internal/internal.crt"
+        src: "{{ kolla_certificates_dir }}/private/external/external.crt"
+        dest: "{{ kolla_certificates_dir }}/private/internal/internal.crt"
         remote_src: yes
         mode: "0660"
     - name: Copy the external certificate key to be the internal when internal + external are same network
       copy:
-        src: "{{ certificates_dir }}/private/external/external.key"
-        dest: "{{ certificates_dir }}/private/internal/internal.key"
+        src: "{{ kolla_certificates_dir }}/private/external/external.key"
+        dest: "{{ kolla_certificates_dir }}/private/internal/internal.key"
         remote_src: yes
         mode: "0660"
     - name: Copy the external PEM file to be the internal when internal + external are same network
@@ -93,38 +105,72 @@
     - name: Creating internal SSL configuration file
       template:
         src: "{{ item }}.j2"
-        dest: "{{ certificates_dir }}/{{ item }}"
+        dest: "{{ kolla_certificates_dir }}/{{ item }}"
         mode: "0660"
       with_items:
         - "openssl-kolla-internal.cnf"
     - name: Creating internal Key
       command: creates="{{ item }}" openssl genrsa -out {{ item }}
       with_items:
-        - "{{ certificates_dir }}/private/internal/internal.key"
+        - "{{ kolla_certificates_dir }}/private/internal/internal.key"
     - name: Setting permissions on internal key
       file:
-        path: "{{ certificates_dir }}/private/internal/internal.key"
+        path: "{{ kolla_certificates_dir }}/private/internal/internal.key"
         mode: "0660"
         state: file
     - name: Creating internal Server Certificate
       command: creates="{{ item }}" openssl req -new -nodes -sha256 -x509 \
-        -config {{ certificates_dir }}/openssl-kolla-internal.cnf \
+        -config {{ kolla_certificates_dir }}/openssl-kolla-internal.cnf \
         -days 3650 \
         -extensions v3_req \
-        -key {{ certificates_dir }}/private/internal/internal.key \
+        -key {{ kolla_certificates_dir }}/private/internal/internal.key \
         -out {{ item }}
       with_items:
-        - "{{ certificates_dir }}/private/internal/internal.crt"
+        - "{{ kolla_certificates_dir }}/private/internal/internal.crt"
     - name: Creating internal CA Certificate File
       copy:
-        src: "{{ certificates_dir }}/private/internal/internal.crt"
+        src: "{{ kolla_certificates_dir }}/private/internal/internal.crt"
         dest: "{{ kolla_internal_fqdn_cacert }}"
         mode: "0660"
     - name: Creating internal Server PEM File
       assemble:
-        src: "{{ certificates_dir }}/private/internal"
+        src: "{{ kolla_certificates_dir }}/private/internal"
         dest: "{{ kolla_internal_fqdn_cert }}"
         mode: "0660"
   when:
     - kolla_enable_tls_internal | bool
     - not kolla_same_external_internal_vip | bool
+
+- block:
+    - name: Creating backend SSL configuration file
+      template:
+        src: "{{ item }}.j2"
+        dest: "{{ kolla_certificates_dir }}/{{ item }}"
+        mode: "0660"
+      with_items:
+        - "openssl-kolla-backend.cnf"
+    - name: Creating backend Key
+      command: creates="{{ item }}" openssl genrsa -out {{ item }}
+      with_items:
+        - "{{ kolla_tls_backend_key }}"
+    - name: Setting permissions on backend key
+      file:
+        path: "{{ kolla_tls_backend_key }}"
+        mode: "0660"
+        state: file
+    - name: Creating backend Server Certificate
+      command: creates="{{ item }}" openssl req -new -nodes -sha256 -x509 \
+        -config {{ kolla_certificates_dir }}/openssl-kolla-backend.cnf \
+        -days 3650 \
+        -extensions v3_req \
+        -key {{ kolla_tls_backend_key }} \
+        -out {{ item }}
+      with_items:
+        - "{{ kolla_tls_backend_cert }}"
+    - name: Creating backend Certificate file to be included in container trusted ca-certificates
+      copy:
+        src: "{{ kolla_tls_backend_cert }}"
+        dest: "{{ kolla_certificates_dir }}/ca/backend-cert.crt"
+        mode: "0660"
+  when:
+    - kolla_enable_tls_backend | bool
diff --git a/ansible/roles/certificates/templates/openssl-kolla-backend.cnf.j2 b/ansible/roles/certificates/templates/openssl-kolla-backend.cnf.j2
new file mode 100644
index 0000000000..bd862832ad
--- /dev/null
+++ b/ansible/roles/certificates/templates/openssl-kolla-backend.cnf.j2
@@ -0,0 +1,18 @@
+[req]
+prompt = no
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+
+[req_distinguished_name]
+countryName = US
+stateOrProvinceName = NC
+localityName = RTP
+organizationalUnitName = kolla
+
+[v3_req]
+subjectAltName = @alt_names
+
+[alt_names]
+{% for host in groups['tls-backend']%}
+IP.{{ loop.index }} = {{ 'api' | kolla_address(host) }}
+{% endfor %}
diff --git a/ansible/roles/haproxy-config/defaults/main.yml b/ansible/roles/haproxy-config/defaults/main.yml
index 7c2e54895b..97ef2a0998 100644
--- a/ansible/roles/haproxy-config/defaults/main.yml
+++ b/ansible/roles/haproxy-config/defaults/main.yml
@@ -13,3 +13,4 @@ haproxy_backend_http_extra: []
 haproxy_backend_tcp_extra: []
 
 haproxy_health_check: "check inter 2000 rise 2 fall 5"
+haproxy_health_check_ssl: "check check-ssl inter 2000 rise 2 fall 5"
diff --git a/ansible/roles/haproxy-config/templates/haproxy_single_service_listen.cfg.j2 b/ansible/roles/haproxy-config/templates/haproxy_single_service_listen.cfg.j2
index b1b133dadf..16076da504 100644
--- a/ansible/roles/haproxy-config/templates/haproxy_single_service_listen.cfg.j2
+++ b/ansible/roles/haproxy-config/templates/haproxy_single_service_listen.cfg.j2
@@ -10,7 +10,7 @@ userlist {{ service_name }}-user
 {%- macro listen_macro(service_name, service_port, listen_port,
                        service_mode, external,
                        haproxy_http_extra, haproxy_tcp_extra, host_group,
-                       custom_member_list, auth_user, auth_pass) %}
+                       custom_member_list, auth_user, auth_pass, tls_backend) %}
 listen {{ service_name }}
     {% if service_mode == 'redirect' %}
     mode http
@@ -59,10 +59,21 @@ listen {{ service_name }}
     {{ custom_member }}
             {% endfor %}
         {% else %}
+            {% set backend_tls_info = '' %}
+            {% if tls_backend|bool %}
+                {% set haproxy_health_check_final = haproxy_health_check_ssl %}
+                {% if kolla_verify_tls_backend|bool %}
+                    {% set backend_tls_info = 'ssl verify required ca-file %s'|format(haproxy_backend_cacert) %}
+                {% else %}
+                    {% set backend_tls_info = 'ssl verify none' %}
+                {% endif %}
+            {% else %}
+                {% set haproxy_health_check_final = haproxy_health_check %}
+            {% endif %}
             {% for host in groups[host_group] %}
                 {% set host_name = hostvars[host]['ansible_hostname'] %}
                 {% set host_ip = 'api' | kolla_address(host) %}
-    server {{ host_name }} {{ host_ip }}:{{ listen_port }} {{ haproxy_health_check }}
+    server {{ host_name }} {{ host_ip }}:{{ listen_port }} {{ haproxy_health_check_final }} {{ backend_tls_info }}
             {% endfor %}
         {% endif %}
     {% endif %}
@@ -86,6 +97,7 @@ listen {{ service_name }}
         {# Additional options can be defined in config, and are additive to the global extras #}
         {% set haproxy_tcp_extra = haproxy_service.frontend_tcp_extra|default([]) + haproxy_service.backend_tcp_extra|default([]) + haproxy_frontend_tcp_extra + haproxy_backend_tcp_extra %}
         {% set haproxy_http_extra = haproxy_service.frontend_http_extra|default([]) + haproxy_service.backend_http_extra|default([]) + haproxy_frontend_http_extra + haproxy_backend_http_extra %}
+        {% set tls_backend = haproxy_service.tls_backend|default(false) %}
         {# Allow for basic auth #}
         {% set auth_user = haproxy_service.auth_user|default() %}
         {% set auth_pass = haproxy_service.auth_pass|default() %}
@@ -94,6 +106,6 @@ listen {{ service_name }}
         {% endif %}
 {{ listen_macro(haproxy_name, haproxy_service.port, listen_port,
                 mode, external, haproxy_http_extra, haproxy_tcp_extra,
-                host_group, custom_member_list, auth_user, auth_pass) }}
+                host_group, custom_member_list, auth_user, auth_pass, tls_backend) }}
     {% endif %}
 {%- endfor -%}
diff --git a/ansible/roles/haproxy-config/templates/haproxy_single_service_split.cfg.j2 b/ansible/roles/haproxy-config/templates/haproxy_single_service_split.cfg.j2
index 27b63e4da6..ec269a307a 100644
--- a/ansible/roles/haproxy-config/templates/haproxy_single_service_split.cfg.j2
+++ b/ansible/roles/haproxy-config/templates/haproxy_single_service_split.cfg.j2
@@ -53,7 +53,7 @@ frontend {{ service_name }}_front
 
 {%- macro backend_macro(service_name, listen_port, service_mode, host_group,
                         custom_member_list, backend_http_extra,
-                        backend_tcp_extra, auth_user, auth_pass) %}
+                        backend_tcp_extra, auth_user, auth_pass, tls_backend) %}
 backend {{ service_name }}_back
     {% if service_mode == 'redirect' %}
     mode http
@@ -79,10 +79,21 @@ backend {{ service_name }}_back
     {{ custom_member }}
         {% endfor %}
     {% else %}
+        {% set backend_tls_info = '' %}
+        {% if tls_backend|bool %}
+            {% set haproxy_health_check_final = haproxy_health_check_ssl %}
+            {% if kolla_verify_tls_backend|bool %}
+                {% set backend_tls_info = 'ssl verify required ca-file %s'|format(haproxy_backend_cacert) %}
+            {% else %}
+                {% set backend_tls_info = 'ssl verify none' %}
+            {% endif %}
+        {% else %}
+            {% set haproxy_health_check_final = haproxy_health_check %}
+        {% endif %}
         {% for host in groups[host_group] %}
             {% set host_name = hostvars[host]['ansible_hostname'] %}
             {% set host_ip = 'api' | kolla_address(host) %}
-    server {{ host_name }} {{ host_ip }}:{{ listen_port }} {{ haproxy_health_check }}
+    server {{ host_name }} {{ host_ip }}:{{ listen_port }} {{ haproxy_health_check_final }} {{ backend_tls_info }}
         {% endfor %}
     {% endif %}
 {% endmacro %}
@@ -107,6 +118,7 @@ backend {{ service_name }}_back
         {% set backend_tcp_extra = haproxy_service.backend_tcp_extra|default([]) %}
         {% set frontend_http_extra = haproxy_service.frontend_http_extra|default([]) + haproxy_frontend_http_extra %}
         {% set backend_http_extra = haproxy_service.backend_http_extra|default([]) %}
+        {% set tls_backend = haproxy_service.tls_backend|default(false) %}
         {# Allow for basic auth #}
         {% set auth_user = haproxy_service.auth_user|default() %}
         {% set auth_pass = haproxy_service.auth_pass|default() %}
@@ -119,7 +131,7 @@ backend {{ service_name }}_back
         {% if haproxy_service.mode != 'redirect' %}
 {{ backend_macro(haproxy_name, listen_port, mode, host_group,
                  custom_member_list, backend_http_extra, backend_tcp_extra,
-                 auth_user, auth_pass) }}
+                 auth_user, auth_pass, tls_backend) }}
         {% endif %}
     {% endif %}
 {%- endfor -%}
diff --git a/ansible/roles/haproxy/tasks/config.yml b/ansible/roles/haproxy/tasks/config.yml
index 99ea810fd2..70cc542adf 100644
--- a/ansible/roles/haproxy/tasks/config.yml
+++ b/ansible/roles/haproxy/tasks/config.yml
@@ -125,6 +125,20 @@
   notify:
     - Restart haproxy container
 
+- name: Copying over extra CA certificates
+  vars:
+    service: "{{ haproxy_services['haproxy'] }}"
+  become: true
+  copy:
+    src: "{{ kolla_certificates_dir }}/ca/"
+    dest: "{{ node_config_directory }}/haproxy/ca-certificates"
+    mode: "0644"
+  when:
+    - inventory_hostname in groups[service.group]
+    - kolla_copy_ca_into_containers | bool
+  notify:
+    - Restart haproxy container
+
 - name: Copying over haproxy start script
   vars:
     service: "{{ haproxy_services['haproxy'] }}"
diff --git a/ansible/roles/haproxy/templates/haproxy_main.cfg.j2 b/ansible/roles/haproxy/templates/haproxy_main.cfg.j2
index 4fa141783e..815fc05364 100644
--- a/ansible/roles/haproxy/templates/haproxy_main.cfg.j2
+++ b/ansible/roles/haproxy/templates/haproxy_main.cfg.j2
@@ -18,6 +18,9 @@ global
     ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
     tune.ssl.default-dh-param 4096
     {% endif %}
+    {% if kolla_enable_tls_internal | bool or kolla_enable_tls_external | bool %}
+    ca-base {{ haproxy_backend_cacert_dir }}
+    {% endif %}
 
 defaults
     log global
diff --git a/ansible/roles/keystone/defaults/main.yml b/ansible/roles/keystone/defaults/main.yml
index 717ee20ffc..f58a7fc498 100644
--- a/ansible/roles/keystone/defaults/main.yml
+++ b/ansible/roles/keystone/defaults/main.yml
@@ -14,18 +14,21 @@ keystone_services:
         enabled: "{{ enable_keystone }}"
         mode: "http"
         external: false
+        tls_backend: "{{ keystone_enable_tls_backend }}"
         port: "{{ keystone_public_port }}"
         listen_port: "{{ keystone_public_listen_port }}"
       keystone_external:
         enabled: "{{ enable_keystone }}"
         mode: "http"
         external: true
+        tls_backend: "{{ keystone_enable_tls_backend }}"
         port: "{{ keystone_public_port }}"
         listen_port: "{{ keystone_public_listen_port }}"
       keystone_admin:
         enabled: "{{ enable_keystone }}"
         mode: "http"
         external: false
+        tls_backend: "{{ keystone_enable_tls_backend }}"
         port: "{{ keystone_admin_port }}"
         listen_port: "{{ keystone_admin_listen_port }}"
   keystone-ssh:
@@ -141,3 +144,8 @@ keystone_ks_services:
       - {'interface': 'admin', 'url': '{{ keystone_admin_url }}'}
       - {'interface': 'internal', 'url': '{{ keystone_internal_url }}'}
       - {'interface': 'public', 'url': '{{ keystone_public_url }}'}
+
+####################
+# TLS
+####################
+keystone_enable_tls_backend: "{{ kolla_enable_tls_backend }}"
diff --git a/ansible/roles/keystone/tasks/config.yml b/ansible/roles/keystone/tasks/config.yml
index d31d1d2017..b47b77f4f0 100644
--- a/ansible/roles/keystone/tasks/config.yml
+++ b/ansible/roles/keystone/tasks/config.yml
@@ -38,19 +38,9 @@
   run_once: True
   register: keystone_domain_directory
 
-- name: Copying over extra CA certificates
-  become: true
-  copy:
-    src: "{{ node_config }}/certificates/ca/"
-    dest: "{{ node_config_directory }}/{{ item.key }}/ca-certificates"
-    mode: "0644"
+- include_tasks: copy-certs.yml
   when:
-    - item.value.enabled | bool
-    - inventory_hostname in groups[item.value.group]
-    - kolla_copy_ca_into_containers | bool
-  with_dict: "{{ keystone_services }}"
-  notify:
-    - "Restart {{ item.key }} container"
+    - kolla_copy_ca_into_containers | bool or keystone_enable_tls_backend | bool
 
 - name: Copying over config.json files for services
   template:
diff --git a/ansible/roles/keystone/tasks/copy-certs.yml b/ansible/roles/keystone/tasks/copy-certs.yml
new file mode 100644
index 0000000000..7fd52ba30a
--- /dev/null
+++ b/ansible/roles/keystone/tasks/copy-certs.yml
@@ -0,0 +1,6 @@
+---
+- name: "Copy certificates and keys for {{ project_name }}"
+  import_role:
+    role: service-cert-copy
+  vars:
+    project_services: "{{ keystone_services }}"
diff --git a/ansible/roles/keystone/templates/keystone.json.j2 b/ansible/roles/keystone/templates/keystone.json.j2
index 4269d7e0fa..6637c5f559 100644
--- a/ansible/roles/keystone/templates/keystone.json.j2
+++ b/ansible/roles/keystone/templates/keystone.json.j2
@@ -34,7 +34,19 @@
             "dest": "/etc/{{ keystone_dir }}/wsgi-keystone.conf",
             "owner": "keystone",
             "perm": "0600"
-        }
+        }{% if keystone_enable_tls_backend | bool %},
+        {
+            "source": "{{ container_config_directory }}/keystone-cert.pem",
+            "dest": "/etc/keystone/certs/keystone-cert.pem",
+            "owner": "keystone",
+            "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/keystone-key.pem",
+            "dest": "/etc/keystone/certs/keystone-key.pem",
+            "owner": "keystone",
+            "perm": "0600"
+        }{% endif %}
     ],
     "permissions": [
         {
diff --git a/ansible/roles/keystone/templates/wsgi-keystone.conf.j2 b/ansible/roles/keystone/templates/wsgi-keystone.conf.j2
index 97c12ada51..17399814e0 100644
--- a/ansible/roles/keystone/templates/wsgi-keystone.conf.j2
+++ b/ansible/roles/keystone/templates/wsgi-keystone.conf.j2
@@ -5,6 +5,9 @@
 {% set python_path = '/var/lib/kolla/venv/lib/python' + distro_python_version + '/site-packages' %}
 {% endif %}
 {% set binary_path = '/usr/bin' if keystone_install_type == 'binary' else '/var/lib/kolla/venv/bin' %}
+{% if keystone_enable_tls_backend | bool %}
+LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
+{% endif %}
 Listen {{ api_interface_address | put_address_in_context('url') }}:{{ keystone_public_listen_port }}
 Listen {{ api_interface_address | put_address_in_context('url') }}:{{ keystone_admin_listen_port }}
 
@@ -42,6 +45,12 @@ LogLevel info
     ErrorLog "{{ keystone_log_dir }}/keystone-apache-public-error.log"
     LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" logformat
     CustomLog "{{ keystone_log_dir }}/keystone-apache-public-access.log" logformat
+
+{% if keystone_enable_tls_backend | bool %}
+    SSLEngine on
+    SSLCertificateFile /etc/keystone/certs/keystone-cert.pem
+    SSLCertificateKeyFile /etc/keystone/certs/keystone-key.pem
+{% endif %}
 </VirtualHost>
 
 <VirtualHost *:{{ keystone_admin_listen_port }}>
@@ -56,4 +65,10 @@ LogLevel info
     ErrorLog "{{ keystone_log_dir }}/keystone-apache-admin-error.log"
     LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" logformat
     CustomLog "{{ keystone_log_dir }}/keystone-apache-admin-access.log" logformat
+
+{% if keystone_enable_tls_backend | bool %}
+    SSLEngine on
+    SSLCertificateFile /etc/keystone/certs/keystone-cert.pem
+    SSLCertificateKeyFile /etc/keystone/certs/keystone-key.pem
+{% endif %}
 </VirtualHost>
diff --git a/ansible/roles/service-cert-copy/tasks/main.yml b/ansible/roles/service-cert-copy/tasks/main.yml
new file mode 100644
index 0000000000..c8af5d50a6
--- /dev/null
+++ b/ansible/roles/service-cert-copy/tasks/main.yml
@@ -0,0 +1,54 @@
+---
+- name: "{{ project_name }} | Copying over extra CA certificates"
+  become: true
+  copy:
+    src: "{{ kolla_certificates_dir }}/ca/"
+    dest: "{{ node_config_directory }}/{{ item.key }}/ca-certificates"
+    mode: "0644"
+  when:
+    - kolla_copy_ca_into_containers | bool
+  with_dict: "{{ project_services | select_services_enabled_and_mapped_to_host }}"
+  notify:
+    - "Restart {{ item.key }} container"
+
+- name: "{{ project_name }} | Copying over backend internal TLS certificate"
+  vars:
+    certs:
+      - "{{ kolla_certificates_dir }}/{{ inventory_hostname }}/{{ project_name }}-cert.pem"
+      - "{{ kolla_certificates_dir }}/{{ inventory_hostname }}-cert.pem"
+      - "{{ kolla_certificates_dir }}/{{ project_name }}-cert.pem"
+      - "{{ kolla_tls_backend_cert }}"
+    backend_tls_cert: "{{ lookup('first_found', certs) }}"
+  copy:
+    src: "{{ backend_tls_cert }}"
+    dest: "{{ node_config_directory }}/{{ item.key }}/{{ project_name }}-cert.pem"
+    mode: "0644"
+  become: true
+  when:
+    - item.value.haproxy is defined
+    - item.value.haproxy.values() | selectattr('enabled', 'defined') | map(attribute='enabled') | map('bool') | select | list | length > 0
+    - item.value.haproxy.values() | selectattr('tls_backend', 'defined') | map(attribute='tls_backend') | map('bool') | select | list | length > 0
+  with_dict: "{{ project_services | select_services_enabled_and_mapped_to_host }}"
+  notify:
+    - "Restart {{ item.key }} container"
+
+- name: "{{ project_name }} | Copying over backend internal TLS key"
+  vars:
+    keys:
+      - "{{ kolla_certificates_dir }}/{{ inventory_hostname }}/{{ project_name }}-key.pem"
+      - "{{ kolla_certificates_dir }}/{{ inventory_hostname }}-key.pem"
+      - "{{ kolla_certificates_dir }}/{{ project_name }}-key.pem"
+      - "{{ kolla_tls_backend_key }}"
+    backend_tls_key: "{{ lookup('first_found', keys) }}"
+  copy:
+    src: "{{ backend_tls_key }}"
+    dest: "{{ node_config_directory }}/{{ item.key }}/{{ project_name }}-key.pem"
+    mode: "0600"
+  become: true
+  when:
+    - item.value.haproxy is defined
+    - item.value.haproxy.values() | selectattr('enabled', 'defined') | map(attribute='enabled') | map('bool') | select | list | length > 0
+    - item.value.haproxy.values() | selectattr('tls_backend', 'defined') | map(attribute='tls_backend') | map('bool') | select | list | length > 0
+  with_dict: "{{ project_services | select_services_enabled_and_mapped_to_host }}"
+  notify:
+    - "Restart {{ item.key }} container"
diff --git a/doc/source/admin/advanced-configuration.rst b/doc/source/admin/advanced-configuration.rst
index 765ed2f69b..34c21a06ed 100644
--- a/doc/source/admin/advanced-configuration.rst
+++ b/doc/source/admin/advanced-configuration.rst
@@ -99,12 +99,12 @@ The default for TLS is disabled, to enable TLS networking:
 .. code-block:: yaml
 
    kolla_enable_tls_external: "yes"
-   kolla_external_fqdn_cert: "{{ node_config }}/certificates/mycert.pem"
+   kolla_external_fqdn_cert: "{{ kolla_certificates_dir }}/mycert.pem"
 
    and/or
 
    kolla_enable_tls_internal: "yes"
-   kolla_internal_fqdn_cert: "{{ node_config }}/certificates/mycert-internal.pem"
+   kolla_internal_fqdn_cert: "{{ kolla_certificates_dir }}/mycert-internal.pem"
 
 
 .. note::
@@ -181,7 +181,7 @@ service containers to enable trust for those CA certificates. This is required
 for any certificates that are either self-signed or signed by a private CA,
 and are not already present in the service image trust store.
 
-All certificate file names will have the "kolla-customca-" prefix appended to
+All certificate file names will have the "kolla-customca-" prefix prepended to
 it when it is copied into the containers. For example, if a certificate file is
 named "internal.crt", it will be named "kolla-customca-internal.crt" in the
 containers.
@@ -192,6 +192,11 @@ the ``/usr/local/share/ca-certificates/`` directory.
 For Centos and Red Hat Linux containers, the certificate files will be copied
 to the ``/etc/pki/ca-trust/source/anchors/`` directory.
 
+In addition, the ``openstack_cacert`` should be configured with the path to
+the cacert in the container. For example, if the self-signed certificate task
+was used and the deployment is on ubuntu, the path would be:
+"/etc/pki/ca-trust/source/anchors/kolla-customca-haproxy-internal.crt"
+
 .. _service-config:
 
 OpenStack Service Configuration in Kolla
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index 1d1eb4db93..55c2b1cb01 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -184,11 +184,18 @@
 # allow clients to perform authentication.
 #kolla_enable_tls_internal: "no"
 #kolla_enable_tls_external: "{{ kolla_enable_tls_internal if kolla_same_external_internal_vip | bool else 'no' }}"
-#kolla_external_fqdn_cert: "{{ node_config }}/certificates/haproxy.pem"
-#kolla_internal_fqdn_cert: "{{ node_config }}/certificates/haproxy-internal.pem"
-#kolla_external_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy.crt"
-#kolla_internal_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy-internal.crt"
+#kolla_certificates_dir: "{{ node_config }}/certificates"
+#kolla_external_fqdn_cert: "{{ kolla_certificates_dir }}/haproxy.pem"
+#kolla_internal_fqdn_cert: "{{ kolla_certificates_dir }}/haproxy-internal.pem"
+#kolla_external_fqdn_cacert: "{{ kolla_certificates_dir }}/ca/haproxy.crt"
+#kolla_internal_fqdn_cacert: "{{ kolla_certificates_dir }}/ca/haproxy-internal.crt"
 #kolla_copy_ca_into_containers: "no"
+#kolla_verify_tls_backend: "yes"
+#haproxy_backend_cacert: "{{ 'ca-certificates.crt' if kolla_base_distro in ['debian', 'ubuntu'] else 'ca-bundle.trust.crt' }}"
+#haproxy_backend_cacert_dir: "/etc/ssl/certs"
+#kolla_enable_tls_backend: "no"
+#kolla_tls_backend_cert: "{{ kolla_certificates_dir }}/backend-cert.pem"
+#kolla_tls_backend_key: "{{ kolla_certificates_dir }}/backend-key.pem"
 
 ################
 # Region options
diff --git a/releasenotes/notes/copy-certificate-authority-into-containers-860cbda3384dd731.yaml b/releasenotes/notes/copy-certificate-authority-into-containers-860cbda3384dd731.yaml
index 78c7e11db8..f5019df18f 100644
--- a/releasenotes/notes/copy-certificate-authority-into-containers-860cbda3384dd731.yaml
+++ b/releasenotes/notes/copy-certificate-authority-into-containers-860cbda3384dd731.yaml
@@ -12,10 +12,8 @@ features:
 
 issues:
   - |
-    Python <= 2.7.9 will not trust self-signed or privately signed CAs even
-    if they are added into the OS trusted CA folder and update-ca-trust is
-    executed. This is also true for the Python Requests library, regardless of
-    Python version. For services that run Python <= 2.7.9 or rely on the
-    Python Requests library, either CA verification must be explicitly disabled
-    in the service or the path to the CA certificate must be configured using
-    the ``openstack_cacert`` parameter.
+    Python Requests library will not trust self-signed or privately signed CAs
+    even if they are added into the OS trusted CA folder and update-ca-trust is
+    executed. For services that rely on the Python Requests library, either CA
+    verification must be explicitly disabled in the service or the path to the
+    CA certificate must be configured using the ``openstack_cacert`` parameter.
diff --git a/releasenotes/notes/encrypt-backend-haproxy-keystone-fb96285d74fb464c.yaml b/releasenotes/notes/encrypt-backend-haproxy-keystone-fb96285d74fb464c.yaml
new file mode 100644
index 0000000000..1b78072702
--- /dev/null
+++ b/releasenotes/notes/encrypt-backend-haproxy-keystone-fb96285d74fb464c.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Added configuration options to enable backend TLS encryption from HAProxy
+    to the Keystone service. When used in conjunction with enabling TLS for
+    service API endpoints, network communcation will be encrypted end to end,
+    from client through HAProxy to the Keystone service.
diff --git a/tests/check-config.sh b/tests/check-config.sh
index 4bc081660c..de6577e08f 100755
--- a/tests/check-config.sh
+++ b/tests/check-config.sh
@@ -16,6 +16,8 @@ function check_config {
     for f in $(sudo find /etc/kolla \
                 -not -regex /etc/kolla/config.* \
                 -not -regex /etc/kolla/certificates.* \
+                -not -regex .*pem \
+                -not -regex .*key \
                 -not -regex ".*ca-certificates.*" \
                 -not -path /etc/kolla \
                 -not -name admin-openrc.sh \
diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2
index e1217ba4b2..3b0ac02391 100644
--- a/tests/templates/globals-default.j2
+++ b/tests/templates/globals-default.j2
@@ -117,8 +117,8 @@ ceph_nova_user: "cinder"
 {% if tls_enabled %}
 kolla_enable_tls_external: "yes"
 kolla_enable_tls_internal: "yes"
-kolla_verify_internal_ca_certs: "no"
 kolla_copy_ca_into_containers: "yes"
+kolla_enable_tls_backend: "yes"
 {% if base_distro == "ubuntu" or base_distro == "debian" %}
 openstack_cacert: "/usr/local/share/ca-certificates/kolla-customca-haproxy-internal.crt"
 {% endif %}
diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2
index 6b0c01e8cd..fbc15f1a10 100644
--- a/tests/templates/inventory.j2
+++ b/tests/templates/inventory.j2
@@ -53,6 +53,9 @@ compute
 storage
 monitoring
 
+[tls-backend:children]
+control
+
 # You can explicitly specify which hosts run each project by updating the
 # groups in the sections below. Common services are grouped together.
 [chrony-server:children]