diff --git a/hooks/certificates-relation-changed b/hooks/certificates-relation-changed
new file mode 120000
index 0000000000000000000000000000000000000000..3195386e535c48512196bb8461cbf221c81f7383
--- /dev/null
+++ b/hooks/certificates-relation-changed
@@ -0,0 +1 @@
+horizon_hooks.py
\ No newline at end of file
diff --git a/hooks/certificates-relation-departed b/hooks/certificates-relation-departed
new file mode 120000
index 0000000000000000000000000000000000000000..3195386e535c48512196bb8461cbf221c81f7383
--- /dev/null
+++ b/hooks/certificates-relation-departed
@@ -0,0 +1 @@
+horizon_hooks.py
\ No newline at end of file
diff --git a/hooks/certificates-relation-joined b/hooks/certificates-relation-joined
new file mode 120000
index 0000000000000000000000000000000000000000..3195386e535c48512196bb8461cbf221c81f7383
--- /dev/null
+++ b/hooks/certificates-relation-joined
@@ -0,0 +1 @@
+horizon_hooks.py
\ No newline at end of file
diff --git a/hooks/horizon_contexts.py b/hooks/horizon_contexts.py
index 5fd0ff7b9021078440a854dab30cb64e666cdf3e..f4f19e2a257c7587817ec913fcf86a09adbeaf56 100644
--- a/hooks/horizon_contexts.py
+++ b/hooks/horizon_contexts.py
@@ -52,6 +52,9 @@ VALID_ENDPOINT_TYPES = {
     'ADMINURL': 'adminURL',
 }
 
+SSL_CERT_FILE = '/etc/apache2/ssl/horizon/cert_dashboard'
+SSL_KEY_FILE = '/etc/apache2/ssl/horizon/key_dashboard'
+
 
 class HorizonHAProxyContext(OSContextGenerator):
     def __call__(self):
@@ -231,27 +234,37 @@ class ApacheContext(OSContextGenerator):
 class ApacheSSLContext(OSContextGenerator):
     def __call__(self):
         ''' Grab cert and key from configuration for SSL config '''
-        ca_cert = get_ca_cert()
-        if ca_cert:
+        ctxt = {'ssl_configured': False}
+        use_local_ca = True
+        for rid in relation_ids('certificates'):
+            if related_units(rid):
+                use_local_ca = False
+
+        if use_local_ca:
+            ca_cert = get_ca_cert()
+            if not ca_cert:
+                return ctxt
             install_ca_cert(b64decode(ca_cert))
 
-        ssl_cert, ssl_key = get_cert()
-        if all([ssl_cert, ssl_key]):
-            with open('/etc/ssl/certs/dashboard.cert', 'w') as cert_out:
-                cert_out.write(b64decode(ssl_cert))
-            with open('/etc/ssl/private/dashboard.key', 'w') as key_out:
-                key_out.write(b64decode(ssl_key))
-            os.chmod('/etc/ssl/private/dashboard.key', 0600)
-            ctxt = {
-                'ssl_configured': True,
-                'ssl_cert': '/etc/ssl/certs/dashboard.cert',
-                'ssl_key': '/etc/ssl/private/dashboard.key',
-            }
+            ssl_cert, ssl_key = get_cert()
+            if all([ssl_cert, ssl_key]):
+                with open('/etc/ssl/certs/dashboard.cert', 'w') as cert_out:
+                    cert_out.write(b64decode(ssl_cert))
+                with open('/etc/ssl/private/dashboard.key', 'w') as key_out:
+                    key_out.write(b64decode(ssl_key))
+                os.chmod('/etc/ssl/private/dashboard.key', 0600)
+                ctxt = {
+                    'ssl_configured': True,
+                    'ssl_cert': '/etc/ssl/certs/dashboard.cert',
+                    'ssl_key': '/etc/ssl/private/dashboard.key',
+                }
         else:
-            # Use snakeoil ones by default
-            ctxt = {
-                'ssl_configured': False,
-            }
+            if os.path.exists(SSL_CERT_FILE) and os.path.exists(SSL_KEY_FILE):
+                ctxt = {
+                    'ssl_configured': True,
+                    'ssl_cert': SSL_CERT_FILE,
+                    'ssl_key': SSL_KEY_FILE,
+                }
         return ctxt
 
 
diff --git a/hooks/horizon_hooks.py b/hooks/horizon_hooks.py
index 254a38affe5f1d26c72e356a97ffc53743491e5a..40895cace9e04d4218e79f7d1b71978d642094de 100755
--- a/hooks/horizon_hooks.py
+++ b/hooks/horizon_hooks.py
@@ -39,6 +39,7 @@ from charmhelpers.fetch import (
 )
 from charmhelpers.core.host import (
     lsb_release,
+    service_reload,
 )
 from charmhelpers.contrib.openstack.utils import (
     configure_installation_source,
@@ -72,6 +73,10 @@ from charmhelpers.contrib.network.ip import (
     is_ipv6,
     get_relation_ip,
 )
+from charmhelpers.contrib.openstack.cert_utils import (
+    get_certificate_request,
+    process_certificates,
+)
 from charmhelpers.contrib.hahelpers.apache import install_ca_cert
 from charmhelpers.contrib.hahelpers.cluster import get_hacluster_config
 from charmhelpers.payload.execd import execd_preinstall
@@ -155,6 +160,9 @@ def config_changed():
     check_custom_theme()
     open_port(80)
     open_port(443)
+    for relid in relation_ids('certificates'):
+        for unit in related_units(relid):
+            certs_changed(relation_id=relid, unit=unit)
 
     websso_trusted_dashboard_changed()
 
@@ -397,5 +405,21 @@ def main():
     assess_status(CONFIGS)
 
 
+@hooks.hook('certificates-relation-joined')
+def certs_joined(relation_id=None):
+    relation_set(
+        relation_id=relation_id,
+        relation_settings=get_certificate_request())
+
+
+@hooks.hook('certificates-relation-changed')
+def certs_changed(relation_id=None, unit=None):
+    process_certificates('horizon', relation_id, unit,
+                         custom_hostname_link='dashboard')
+    CONFIGS.write_all()
+    service_reload('apache2')
+    enable_ssl()
+
+
 if __name__ == '__main__':
     main()
diff --git a/metadata.yaml b/metadata.yaml
index 98c1a0a8cedb48ed0333289db7bcd0080827bf7b..e05fc5d187478cd7506999c1ae0d21d6b2094885 100644
--- a/metadata.yaml
+++ b/metadata.yaml
@@ -35,6 +35,8 @@ requires:
     interface: mysql-shared
   websso-fid-service-provider:
     interface: websso-fid-service-provider
+  certificates:
+    interface: tls-certificates
 peers:
   cluster:
     interface: openstack-dashboard-ha
diff --git a/unit_tests/test_actions_openstack_upgrade.py b/unit_tests/test_actions_openstack_upgrade.py
index d30d7e984112c40e5589534032d31d84a7628022..8c75233660303302533a9ee48d50b4c54bae7215 100644
--- a/unit_tests/test_actions_openstack_upgrade.py
+++ b/unit_tests/test_actions_openstack_upgrade.py
@@ -36,6 +36,8 @@ from test_utils import (
 )
 
 TO_PATCH = [
+    'CONFIGS',
+    'do_action_openstack_upgrade',
     'do_openstack_upgrade',
     'config_changed',
 ]
@@ -47,28 +49,25 @@ class TestHorizonUpgradeActions(CharmTestCase):
         super(TestHorizonUpgradeActions, self).setUp(openstack_upgrade,
                                                      TO_PATCH)
 
-    @patch('charmhelpers.contrib.openstack.utils.config')
-    @patch('charmhelpers.contrib.openstack.utils.action_set')
-    @patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available')
-    def test_openstack_upgrade_true(self, upgrade_avail,
-                                    action_set, config):
-        upgrade_avail.return_value = True
-        config.return_value = True
+    def test_openstack_upgrade_true(self):
 
+        self.do_action_openstack_upgrade.return_value = True
         openstack_upgrade.openstack_upgrade()
 
-        self.assertTrue(self.do_openstack_upgrade.called)
-        self.assertTrue(self.config_changed.called)
+        self.do_action_openstack_upgrade.assert_called_once_with(
+            'openstack-dashboard',
+            self.do_openstack_upgrade,
+            self.CONFIGS)
+        self.config_changed.assert_called_once_with()
 
-    @patch('charmhelpers.contrib.openstack.utils.config')
-    @patch('charmhelpers.contrib.openstack.utils.action_set')
-    @patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available')
-    def test_openstack_upgrade_false(self, upgrade_avail,
-                                     action_set, config):
-        upgrade_avail.return_value = True
-        config.return_value = False
+    def test_openstack_upgrade_false(self):
+        self.do_action_openstack_upgrade.return_value = False
 
         openstack_upgrade.openstack_upgrade()
 
+        self.do_action_openstack_upgrade.assert_called_once_with(
+            'openstack-dashboard',
+            self.do_openstack_upgrade,
+            self.CONFIGS)
         self.assertFalse(self.do_openstack_upgrade.called)
         self.assertFalse(self.config_changed.called)
diff --git a/unit_tests/test_horizon_contexts.py b/unit_tests/test_horizon_contexts.py
index 58b9dd4ce5a3749f13a6a223923875aedf923792..8a81a67efb1ba4d4aa174e2eb5e159206214869d 100644
--- a/unit_tests/test_horizon_contexts.py
+++ b/unit_tests/test_horizon_contexts.py
@@ -95,11 +95,13 @@ class TestHorizonContexts(CharmTestCase):
                            'hsts_max_age_seconds': 15768000,
                            'custom_theme': False})
 
-    @patch.object(horizon_contexts, 'get_ca_cert', lambda: None)
+    @patch.object(horizon_contexts, 'get_ca_cert', lambda: 'ca_cert')
+    @patch.object(horizon_contexts, 'install_ca_cert')
     @patch('os.chmod')
-    def test_ApacheSSLContext_enabled(self, _chmod):
+    def test_ApacheSSLContext_enabled(self, _chmod, _install_ca_cert):
+        self.relation_ids.return_value = []
         self.get_cert.return_value = ('cert', 'key')
-        self.b64decode.side_effect = ['cert', 'key']
+        self.b64decode.side_effect = ['ca', 'cert', 'key']
         with patch_open() as (_open, _file):
             self.assertEqual(horizon_contexts.ApacheSSLContext()(),
                              {'ssl_configured': True,
@@ -115,13 +117,27 @@ class TestHorizonContexts(CharmTestCase):
             ])
         # Security check on key permissions
         _chmod.assert_called_with('/etc/ssl/private/dashboard.key', 0o600)
+        _install_ca_cert.assert_called_once()
 
     @patch.object(horizon_contexts, 'get_ca_cert', lambda: None)
     def test_ApacheSSLContext_disabled(self):
+        self.relation_ids.return_value = []
         self.get_cert.return_value = (None, None)
         self.assertEqual(horizon_contexts.ApacheSSLContext()(),
                          {'ssl_configured': False})
 
+    @patch.object(horizon_contexts.os.path, 'exists')
+    def test_ApacheSSLContext_vault(self, _exists):
+        _exists.return_value = True
+        self.relation_ids.return_value = ['certificates:60']
+        self.related_units.return_value = ['vault/0']
+        self.assertEqual(
+            horizon_contexts.ApacheSSLContext()(),
+            {
+                'ssl_configured': True,
+                'ssl_cert': '/etc/apache2/ssl/horizon/cert_dashboard',
+                'ssl_key': '/etc/apache2/ssl/horizon/key_dashboard'})
+
     def test_HorizonContext_defaults(self):
         self.assertEqual(horizon_contexts.HorizonContext()(),
                          {'compress_offline': True, 'debug': False,
diff --git a/unit_tests/test_horizon_hooks.py b/unit_tests/test_horizon_hooks.py
index e7c20f2428e63589a9c08ee71665ce192a379d9e..53446b490fab07f6614d91dcd6a4dabe17be8047 100644
--- a/unit_tests/test_horizon_hooks.py
+++ b/unit_tests/test_horizon_hooks.py
@@ -273,6 +273,7 @@ class TestHorizonHooks(CharmTestCase):
                 'identity-service': [
                     'identity/0',
                 ],
+                'certificates': [],
             }[rname]
         self.relation_ids.side_effect = relation_ids_side_effect
 
@@ -287,7 +288,6 @@ class TestHorizonHooks(CharmTestCase):
                 'webroot': '/horizon',
             }[key]
         self.config.side_effect = config_side_effect
-
         self.openstack_upgrade_available.return_value = False
         self._call_hook('config-changed')
         _joined.assert_called_with('identity/0')