diff --git a/extraconfig/nova_metadata/krb-service-principals.yaml b/extraconfig/nova_metadata/krb-service-principals.yaml
new file mode 100644
index 0000000000..c66e6460cc
--- /dev/null
+++ b/extraconfig/nova_metadata/krb-service-principals.yaml
@@ -0,0 +1,84 @@
+heat_template_version: ocata
+description: 'Generates the relevant service principals for a server'
+
+parameters:
+  RoleData:
+     type: json
+     description: the list containing the 'role_data' output for the ServiceChain
+
+  # Coming from parameter_defaults
+  CloudName:
+    default: overcloud.localdomain
+    description: The DNS name of this cloud. E.g. ci-overcloud.tripleo.org
+    type: string
+  CloudNameInternal:
+    default: overcloud.internalapi.localdomain
+    description: >
+      The DNS name of this cloud's internal API endpoint. E.g.
+      'ci-overcloud.internalapi.tripleo.org'.
+    type: string
+  CloudNameStorage:
+    default: overcloud.storage.localdomain
+    description: >
+      The DNS name of this cloud's storage endpoint. E.g.
+      'ci-overcloud.storage.tripleo.org'.
+    type: string
+  CloudNameStorageManagement:
+    default: overcloud.storagemgmt.localdomain
+    description: >
+      The DNS name of this cloud's storage management endpoint. E.g.
+      'ci-overcloud.storagemgmt.tripleo.org'.
+    type: string
+  CloudNameCtlplane:
+    default: overcloud.ctlplane.localdomain
+    description: >
+      The DNS name of this cloud's storage management endpoint. E.g.
+      'ci-overcloud.management.tripleo.org'.
+    type: string
+
+resources:
+
+  IncomingMetadataSettings:
+    type: OS::Heat::Value
+    properties:
+      value:
+        yaql:
+          # Filter null values and values that contain don't contain
+          # 'metadata_settings', get the values from that key and get the
+          # unique ones.
+          expression: list($.data.where($ != null).where($.containsKey('metadata_settings')).metadata_settings.flatten().distinct())
+          data: {get_param: RoleData}
+
+  # Generates entries for nova metadata with the following format:
+  #   'managed_service_<id>' : <service>/<fqdn>
+  # Depending on the requested network
+  IndividualServices:
+    type: OS::Heat::Value
+    properties:
+      value:
+        yaql:
+          expression: let(fqdns => $.data.fqdns) -> dict($.data.metadata.where($ != null and $.type = 'vip').select([concat('managed_service_', $.service, $.network), concat($.service, '/', $fqdns.get($.network))]))
+          data:
+            metadata: {get_attr: [IncomingMetadataSettings, value]}
+            fqdns:
+              external: {get_param: CloudName}
+              internal_api: {get_param: CloudNameInternal}
+              storage: {get_param: CloudNameStorage}
+              storage_mgmt: {get_param: CloudNameStorageManagement}
+              ctlplane: {get_param: CloudNameCtlplane}
+
+  CompactServices:
+    type: OS::Heat::Value
+    properties:
+      value:
+        yaql:
+          expression: dict($.data.where($ != null and $.type = 'node').select([$.service, $.network.replace('_', '')]).groupBy($[0], $[1]))
+          data: {get_attr: [IncomingMetadataSettings, value]}
+
+outputs:
+  metadata:
+    description: actual metadata entries that will be passed to the server.
+    value:
+      map_merge:
+        - {get_attr: [IndividualServices, value]}
+        - compact_services: {get_attr: [CompactServices, value]}
diff --git a/puppet/services/aodh-api.yaml b/puppet/services/aodh-api.yaml
index 4e735b455b..2c44f4df02 100644
--- a/puppet/services/aodh-api.yaml
+++ b/puppet/services/aodh-api.yaml
@@ -83,3 +83,5 @@ outputs:
         get_attr: [AodhBase, role_data, service_config_settings]
       step_config: |
         include tripleo::profile::base::aodh::api
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]
diff --git a/puppet/services/apache-internal-tls-certmonger.yaml b/puppet/services/apache-internal-tls-certmonger.yaml
index 07ec1b3c7c..97d6ff8ed9 100644
--- a/puppet/services/apache-internal-tls-certmonger.yaml
+++ b/puppet/services/apache-internal-tls-certmonger.yaml
@@ -21,6 +21,22 @@ parameters:
                  via parameter_defaults in the resource registry.
     type: json
 
+resources:
+
+  ApacheNetworks:
+    type: OS::Heat::Value
+    properties:
+      value:
+        # NOTE(jaosorior) Get unique network names to create
+        # certificates for those. We skip the tenant network since
+        # we don't need a certificate for that, and the external
+        # network will be handled in another template.
+        yaql:
+          expression: list($.data.map.items().map($1[1])).distinct().where($ != external and $ != tenant)
+          data:
+            map:
+              get_param: ServiceNetMap
+
 outputs:
   role_data:
     description: Role data for the Apache role.
@@ -38,13 +54,12 @@ outputs:
                   hostname: "%{hiera('fqdn_NETWORK')}"
                   principal: "HTTP/%{hiera('fqdn_NETWORK')}"
               for_each:
-                NETWORK:
-                  # NOTE(jaosorior) Get unique network names to create
-                  # certificates for those. We skip the tenant network since
-                  # we don't need a certificate for that, and the external
-                  # network will be handled in another template.
-                  yaql:
-                    expression: list($.data.map.items().map($1[1])).distinct().where($ != external and $ != tenant)
-                    data:
-                      map:
-                        get_param: ServiceNetMap
+                NETWORK: {get_attr: [ApacheNetworks, value]}
+      metadata_settings:
+        repeat:
+          template:
+            - service: HTTP
+              network: $NETWORK
+              type: node
+          for_each:
+            $NETWORK: {get_attr: [ApacheNetworks, value]}
diff --git a/puppet/services/apache.yaml b/puppet/services/apache.yaml
index 2e95dcb0b3..82e0c5ff4c 100644
--- a/puppet/services/apache.yaml
+++ b/puppet/services/apache.yaml
@@ -64,3 +64,5 @@ outputs:
             apache::mod::prefork::serverlimit: { get_param: ApacheServerLimit }
             apache::mod::remoteip::proxy_ips:
               - "%{hiera('apache_remote_proxy_ips_network')}"
+      metadata_settings:
+        get_attr: [ApacheTLS, role_data, metadata_settings]
diff --git a/puppet/services/barbican-api.yaml b/puppet/services/barbican-api.yaml
index 000a744c78..1f220e6b85 100644
--- a/puppet/services/barbican-api.yaml
+++ b/puppet/services/barbican-api.yaml
@@ -144,3 +144,5 @@ outputs:
             get_param: [EndpointMap, BarbicanInternal, uri]
           cinder::api::keymgr_encryption_auth_url:
             get_param: [EndpointMap, KeystoneV3Internal, uri]
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]
diff --git a/puppet/services/ceilometer-api.yaml b/puppet/services/ceilometer-api.yaml
index 63e02d4fe4..f774167f74 100644
--- a/puppet/services/ceilometer-api.yaml
+++ b/puppet/services/ceilometer-api.yaml
@@ -90,3 +90,5 @@ outputs:
         get_attr: [CeilometerServiceBase, role_data, service_config_settings]
       step_config: |
         include ::tripleo::profile::base::ceilometer::api
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]
diff --git a/puppet/services/cinder-api.yaml b/puppet/services/cinder-api.yaml
index eee04ce091..a5c912ede6 100644
--- a/puppet/services/cinder-api.yaml
+++ b/puppet/services/cinder-api.yaml
@@ -146,6 +146,8 @@ outputs:
           cinder::db::mysql::allowed_hosts:
             - '%'
             - "%{hiera('mysql_bind_host')}"
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]
       upgrade_tasks:
         - name: check for cinder running under apache (post upgrade)
           tags: step2
diff --git a/puppet/services/database/mysql-internal-tls-certmonger.yaml b/puppet/services/database/mysql-internal-tls-certmonger.yaml
index 56d037e7b7..9f7eaf5742 100644
--- a/puppet/services/database/mysql-internal-tls-certmonger.yaml
+++ b/puppet/services/database/mysql-internal-tls-certmonger.yaml
@@ -41,3 +41,7 @@ outputs:
               template: "mysql/%{hiera('cloud_name_NETWORK')}"
               params:
                 NETWORK: {get_param: [ServiceNetMap, MysqlNetwork]}
+      metadata_settings:
+        - service: mysql
+          network: {get_param: [ServiceNetMap, MysqlNetwork]}
+          type: vip
diff --git a/puppet/services/database/mysql.yaml b/puppet/services/database/mysql.yaml
index 7e12894fea..8c4042d967 100644
--- a/puppet/services/database/mysql.yaml
+++ b/puppet/services/database/mysql.yaml
@@ -104,4 +104,6 @@ outputs:
         - name: Start service
           tags: step4
           service: name=mariadb state=started
+      metadata_settings:
+        get_attr: [MySQLTLS, role_data, metadata_settings]
 
diff --git a/puppet/services/gnocchi-api.yaml b/puppet/services/gnocchi-api.yaml
index 3929e0057b..ae384ce04f 100644
--- a/puppet/services/gnocchi-api.yaml
+++ b/puppet/services/gnocchi-api.yaml
@@ -131,3 +131,5 @@ outputs:
           gnocchi::db::mysql::allowed_hosts:
             - '%'
             - "%{hiera('mysql_bind_host')}"
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]
diff --git a/puppet/services/haproxy-internal-tls-certmonger.yaml b/puppet/services/haproxy-internal-tls-certmonger.yaml
index 774575938a..ae2261632e 100644
--- a/puppet/services/haproxy-internal-tls-certmonger.yaml
+++ b/puppet/services/haproxy-internal-tls-certmonger.yaml
@@ -19,6 +19,22 @@ parameters:
                  via parameter_defaults in the resource registry.
     type: json
 
+resources:
+
+  HAProxyNetworks:
+    type: OS::Heat::Value
+    properties:
+      value:
+        # NOTE(jaosorior) Get unique network names to create
+        # certificates for those. We skip the tenant network since
+        # we don't need a certificate for that, and the external
+        # network will be handled in another template.
+        yaql:
+          expression: list($.data.map.items().map($1[1])).distinct().where($ != external and $ != tenant)
+          data:
+            map:
+              get_param: ServiceNetMap
+
 outputs:
   role_data:
     description: Role data for the HAProxy internal TLS via certmonger role.
@@ -39,13 +55,12 @@ outputs:
                 postsave_cmd: "" # TODO
                 principal: "haproxy/%{hiera('cloud_name_NETWORK')}"
             for_each:
-              NETWORK:
-                # NOTE(jaosorior) Get unique network names to create
-                # certificates for those. We skip the tenant network since
-                # we don't need a certificate for that, and the external
-                # network will be handled in another template.
-                yaql:
-                  expression: list($.data.map.items().map($1[1])).distinct().where($ != external and $ != tenant)
-                  data:
-                    map:
-                      get_param: ServiceNetMap
+              NETWORK: {get_attr: [HAProxyNetworks, value]}
+      metadata_settings:
+        repeat:
+          template:
+          - service: haproxy
+            network: $NETWORK
+            type: vip
+          for_each:
+            $NETWORK: {get_attr: [HAProxyNetworks, value]}
diff --git a/puppet/services/haproxy-public-tls-certmonger.yaml b/puppet/services/haproxy-public-tls-certmonger.yaml
index 227697b9d2..6013b02658 100644
--- a/puppet/services/haproxy-public-tls-certmonger.yaml
+++ b/puppet/services/haproxy-public-tls-certmonger.yaml
@@ -35,3 +35,7 @@ outputs:
           hostname: "%{hiera('cloud_name_external')}"
           postsave_cmd: "" # TODO
           principal: "haproxy/%{hiera('cloud_name_external')}"
+      metadata_settings:
+        - service: haproxy
+          network: external
+          type: vip
diff --git a/puppet/services/haproxy.yaml b/puppet/services/haproxy.yaml
index 9049c90189..981a08d2c2 100644
--- a/puppet/services/haproxy.yaml
+++ b/puppet/services/haproxy.yaml
@@ -84,3 +84,9 @@ outputs:
         - name: Start haproxy service
           tags: step4 # Needed at step 4 for mysql
           service: name=haproxy state=started
+      metadata_settings:
+        yaql:
+          expression: '[].concat(coalesce($.data.internal, []), coalesce($.data.public, []))'
+          data:
+            public: {get_attr: [HAProxyPublicTLS, role_data, metadata_settings]}
+            internal: {get_attr: [HAProxyInternalTLS, role_data, metadata_settings]}
diff --git a/puppet/services/keystone.yaml b/puppet/services/keystone.yaml
index 434f0a3391..b989d5028a 100644
--- a/puppet/services/keystone.yaml
+++ b/puppet/services/keystone.yaml
@@ -313,3 +313,8 @@ outputs:
         - name: Sync keystone DB
           tags: step5
           command: keystone-manage db_sync
+        - name: Start keystone service (running under httpd)
+          tags: step6
+          service: name=httpd state=started
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]
diff --git a/puppet/services/nova-api.yaml b/puppet/services/nova-api.yaml
index 36ac3e083e..892e63dd16 100644
--- a/puppet/services/nova-api.yaml
+++ b/puppet/services/nova-api.yaml
@@ -165,3 +165,5 @@ outputs:
           nova::keystone::auth::admin_url: {get_param: [EndpointMap, NovaAdmin, uri]}
           nova::keystone::auth::password: {get_param: NovaPassword}
           nova::keystone::auth::region: {get_param: KeystoneRegion}
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]
diff --git a/puppet/services/pacemaker/database/mysql.yaml b/puppet/services/pacemaker/database/mysql.yaml
index 511a01abe6..93bf5967bc 100644
--- a/puppet/services/pacemaker/database/mysql.yaml
+++ b/puppet/services/pacemaker/database/mysql.yaml
@@ -53,6 +53,8 @@ outputs:
               get_param: [ServiceNetMap, MysqlNetwork]
       step_config: |
         include ::tripleo::profile::pacemaker::database::mysql
+      metadata_settings:
+        get_attr: [MysqlBase, role_data, metadata_settings]
       upgrade_tasks:
         - name: Check for galera root password
           tags: step0
diff --git a/puppet/services/pacemaker/haproxy.yaml b/puppet/services/pacemaker/haproxy.yaml
index 50da411933..598deaef6f 100644
--- a/puppet/services/pacemaker/haproxy.yaml
+++ b/puppet/services/pacemaker/haproxy.yaml
@@ -40,3 +40,5 @@ outputs:
             tripleo::haproxy::mysql_clustercheck: true
       step_config: |
         include ::tripleo::profile::pacemaker::haproxy
+      metadata_settings:
+        get_attr: [LoadbalancerServiceBase, role_data, metadata_settings]
diff --git a/puppet/services/panko-api.yaml b/puppet/services/panko-api.yaml
index 06284fb204..4b74ad45bf 100644
--- a/puppet/services/panko-api.yaml
+++ b/puppet/services/panko-api.yaml
@@ -82,3 +82,5 @@ outputs:
         get_attr: [PankoBase, role_data, service_config_settings]
       step_config: |
         include tripleo::profile::base::panko::api
+      metadata_settings:
+        get_attr: [ApacheServiceBase, role_data, metadata_settings]