diff --git a/ansible/roles/aodh/defaults/main.yml b/ansible/roles/aodh/defaults/main.yml
index d04fe605c1d972c3148d23cd5f9de58b23c69f4e..fd58d635fc5d2b903ce995d7eb725045054502d0 100644
--- a/ansible/roles/aodh/defaults/main.yml
+++ b/ansible/roles/aodh/defaults/main.yml
@@ -147,3 +147,21 @@ aodh_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 aodh_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 aodh_dev_mode: "{{ kolla_dev_mode }}"
 aodh_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+aodh_ks_services:
+  - name: "aodh"
+    type: "alarming"
+    description: "OpenStack Alarming Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ aodh_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ aodh_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ aodh_public_endpoint }}'}
+
+aodh_ks_users:
+  - project: "service"
+    user: "{{ aodh_keystone_user }}"
+    password: "{{ aodh_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/aodh/tasks/register.yml b/ansible/roles/aodh/tasks/register.yml
index 4cc2bc1fb39ac78df900166b1983168364eec688..3a97d70b3be50edd031037792f1cb3c40d88bdd5 100644
--- a/ansible/roles/aodh/tasks/register.yml
+++ b/ansible/roles/aodh/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the aodh service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "aodh"
-      service_type: "alarming"
-      description: "OpenStack Alarming Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_aodh_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ aodh_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ aodh_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ aodh_public_endpoint }}'}
-
-- name: Creating the aodh project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ aodh_keystone_user }}"
-      password: "{{ aodh_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_aodh_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_aodh_auth }}"
+    service_ks_register_services: "{{ aodh_ks_services }}"
+    service_ks_register_users: "{{ aodh_ks_users }}"
+  tags: always
diff --git a/ansible/roles/barbican/defaults/main.yml b/ansible/roles/barbican/defaults/main.yml
index 4f4d58d6a261303b1e318c90b1765804f9e3a05d..c7349fb95cdbe903389d51914defbeee0d805392 100644
--- a/ansible/roles/barbican/defaults/main.yml
+++ b/ansible/roles/barbican/defaults/main.yml
@@ -115,3 +115,21 @@ barbican_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 barbican_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 barbican_dev_mode: "{{ kolla_dev_mode }}"
 barbican_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+barbican_ks_services:
+  - name: "barbican"
+    type: "key-manager"
+    description: "Barbican Key Management Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ barbican_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ barbican_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ barbican_public_endpoint }}'}
+
+barbican_ks_users:
+  - project: "service"
+    user: "{{ barbican_keystone_user }}"
+    password: "{{ barbican_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/barbican/tasks/register.yml b/ansible/roles/barbican/tasks/register.yml
index 75f0855d7e239d27a21009b64ea6cf920c6d7da1..84cc5d7911d56500356c0cfd9cda568ea0d4a990 100644
--- a/ansible/roles/barbican/tasks/register.yml
+++ b/ansible/roles/barbican/tasks/register.yml
@@ -1,39 +1,11 @@
 ---
-- name: Creating the barbican service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "barbican"
-      service_type: "key-manager"
-      description: "Barbican Key Management Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_barbican_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ barbican_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ barbican_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ barbican_public_endpoint }}'}
-
-- name: Creating the barbican project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ barbican_keystone_user }}"
-      password: "{{ barbican_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_barbican_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_barbican_auth }}"
+    service_ks_register_services: "{{ barbican_ks_services }}"
+    service_ks_register_users: "{{ barbican_ks_users }}"
+  tags: always
 
 - name: Creating default barbican roles
   become: true
diff --git a/ansible/roles/blazar/defaults/main.yml b/ansible/roles/blazar/defaults/main.yml
index 831d4622ced1e602649990d286ff4f312454f941..103b5ca05d015ad22d685e8c48eaa138b83a6748 100644
--- a/ansible/roles/blazar/defaults/main.yml
+++ b/ansible/roles/blazar/defaults/main.yml
@@ -105,3 +105,21 @@ blazar_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 blazar_enabled_notification_topics: "{{ blazar_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+blazar_ks_services:
+  - name: "blazar"
+    type: "reservation"
+    description: "OpenStack Reservation Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ blazar_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ blazar_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ blazar_public_endpoint }}'}
+
+blazar_ks_users:
+  - project: "service"
+    user: "{{ blazar_keystone_user }}"
+    password: "{{ blazar_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/blazar/tasks/register.yml b/ansible/roles/blazar/tasks/register.yml
index 73b216498465fe2f3c14c49a8ec90404645d0296..515bac5a300204a8c3c9d80f8ea28a7c0cfc8470 100644
--- a/ansible/roles/blazar/tasks/register.yml
+++ b/ansible/roles/blazar/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the blazar service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "blazar"
-      service_type: "reservation"
-      description: "OpenStack Reservation Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_blazar_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ blazar_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ blazar_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ blazar_public_endpoint }}'}
-
-- name: Creating the blazar project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ blazar_keystone_user }}"
-      password: "{{ blazar_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_blazar_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_blazar_auth }}"
+    service_ks_register_services: "{{ blazar_ks_services }}"
+    service_ks_register_users: "{{ blazar_ks_users }}"
+  tags: always
diff --git a/ansible/roles/ceilometer/defaults/main.yml b/ansible/roles/ceilometer/defaults/main.yml
index 03cab768c6bfaee3691fc8fb86adcf9a7403fb70..327b736f58f3c27ab34bcaf19c8a1d91fd96e3c8 100644
--- a/ansible/roles/ceilometer/defaults/main.yml
+++ b/ansible/roles/ceilometer/defaults/main.yml
@@ -111,3 +111,13 @@ ceilometer_dev_mode: "{{ kolla_dev_mode }}"
 ceilometer_source_version: "{{ kolla_source_version }}"
 
 ceilometer_custom_meters_local_folder: "meters.d"
+
+####################
+# Keystone
+####################
+
+ceilometer_ks_users:
+  - project: "service"
+    user: "{{ ceilometer_keystone_user }}"
+    password: "{{ ceilometer_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/ceilometer/tasks/register.yml b/ansible/roles/ceilometer/tasks/register.yml
index 76ee2b0d7ac97f87c6e1148ed2271f5f84bdabd3..2a3225c9e46791199b0217305dde75c77974ce78 100644
--- a/ansible/roles/ceilometer/tasks/register.yml
+++ b/ansible/roles/ceilometer/tasks/register.yml
@@ -1,18 +1,10 @@
 ---
-- name: Creating the Ceilometer project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ ceilometer_keystone_user }}"
-      password: "{{ ceilometer_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_ceilometer_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_ceilometer_auth }}"
+    service_ks_register_users: "{{ ceilometer_ks_users }}"
+  tags: always
 
 - name: Associate the ResellerAdmin role and ceilometer user
   become: true
diff --git a/ansible/roles/ceph/defaults/main.yml b/ansible/roles/ceph/defaults/main.yml
index 2c94b9da8af95f25f40a295dd577dbe24c7a5bb8..04d6b9d77b3a62dd626be688a302fbcf3e9d1b4f 100644
--- a/ansible/roles/ceph/defaults/main.yml
+++ b/ansible/roles/ceph/defaults/main.yml
@@ -128,3 +128,22 @@ cephfs_metadata_pool_pgp_num: "{{ ceph_pool_pgp_num }}"
 # Kolla
 ####################
 kolla_ceph_use_udev: True
+
+
+####################
+# Keystone
+####################
+ceph_rgw_ks_services:
+  - name: "swift"
+    type: "object-store"
+    description: "Openstack Object Storage"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ swift_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ swift_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ swift_public_endpoint }}'}
+
+ceph_rgw_ks_users:
+  - project: "service"
+    user: "{{ ceph_rgw_keystone_user }}"
+    password: "{{ ceph_rgw_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/ceph/tasks/start_rgw_keystone.yml b/ansible/roles/ceph/tasks/start_rgw_keystone.yml
index 4027d341ea8ed9c1c13582cbbf15d0ff149fb76f..175e8614b197752a2ff35914e9bee95ad2ca0dd2 100644
--- a/ansible/roles/ceph/tasks/start_rgw_keystone.yml
+++ b/ansible/roles/ceph/tasks/start_rgw_keystone.yml
@@ -1,39 +1,11 @@
 ---
-- name: Creating the Swift service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: kolla_keystone_service
-    module_args:
-      service_name: "swift"
-      service_type: "object-store"
-      description: "Openstack Object Storage"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_ceph_rgw_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ swift_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ swift_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ swift_public_endpoint }}'}
-
-- name: Registering keystone ceph_rgw user
-  become: true
-  kolla_toolbox:
-    module_name: kolla_keystone_user
-    module_args:
-      project: "service"
-      user: "{{ ceph_rgw_keystone_user }}"
-      password: "{{ ceph_rgw_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_ceph_rgw_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_ceph_rgw_auth }}"
+    service_ks_register_services: "{{ ceph_rgw_ks_services }}"
+    service_ks_register_users: "{{ ceph_rgw_ks_users }}"
+  tags: always
 
 - name: Creating the ResellerAdmin role
   become: true
diff --git a/ansible/roles/cinder/defaults/main.yml b/ansible/roles/cinder/defaults/main.yml
index 7df2547e53ca60343fa8b47efefed20d8e561967..5803f4d5d8410b31841decae2901a7ec37e0ba09 100644
--- a/ansible/roles/cinder/defaults/main.yml
+++ b/ansible/roles/cinder/defaults/main.yml
@@ -250,3 +250,28 @@ cinder_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 cinder_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 cinder_dev_mode: "{{ kolla_dev_mode }}"
 cinder_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+cinder_ks_services:
+  - name: "cinderv2"
+    type: "volumev2"
+    description: "Openstack Block Storage"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ cinder_v2_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ cinder_v2_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ cinder_v2_public_endpoint }}'}
+  - name: "cinderv3"
+    type: "volumev3"
+    description: "Openstack Block Storage"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ cinder_v3_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ cinder_v3_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ cinder_v3_public_endpoint }}'}
+
+cinder_ks_users:
+  - project: "service"
+    user: "{{ cinder_keystone_user }}"
+    password: "{{ cinder_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/cinder/tasks/register.yml b/ansible/roles/cinder/tasks/register.yml
index 579b28b9252726ebd38f8e752933752c9fb37ca9..6ac5939430d72683fb094c3fc052480837fca097 100644
--- a/ansible/roles/cinder/tasks/register.yml
+++ b/ansible/roles/cinder/tasks/register.yml
@@ -1,39 +1,8 @@
 ---
-- name: Creating the Cinder service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "{{ item.service_name }}"
-      service_type: "{{ item.service_type }}"
-      description: "Openstack Block Storage"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_cinder_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ cinder_v2_admin_endpoint }}', 'service_name': 'cinderv2', 'service_type': 'volumev2'}
-    - {'interface': 'internal', 'url': '{{ cinder_v2_internal_endpoint }}', 'service_name': 'cinderv2', 'service_type': 'volumev2'}
-    - {'interface': 'public', 'url': '{{ cinder_v2_public_endpoint }}', 'service_name': 'cinderv2', 'service_type': 'volumev2'}
-    - {'interface': 'admin', 'url': '{{ cinder_v3_admin_endpoint }}', 'service_name': 'cinderv3', 'service_type': 'volumev3'}
-    - {'interface': 'internal', 'url': '{{ cinder_v3_internal_endpoint }}', 'service_name': 'cinderv3', 'service_type': 'volumev3'}
-    - {'interface': 'public', 'url': '{{ cinder_v3_public_endpoint }}', 'service_name': 'cinderv3', 'service_type': 'volumev3'}
-
-- name: Creating the Cinder project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ cinder_keystone_user }}"
-      password: "{{ cinder_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_cinder_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_cinder_auth }}"
+    service_ks_register_services: "{{ cinder_ks_services }}"
+    service_ks_register_users: "{{ cinder_ks_users }}"
+  tags: always
diff --git a/ansible/roles/cloudkitty/defaults/main.yml b/ansible/roles/cloudkitty/defaults/main.yml
index 342c7c43600ba433c1b8e64709bfa375c32500f2..440a40a48c06a74d91d31c31dfa71825ac81810e 100644
--- a/ansible/roles/cloudkitty/defaults/main.yml
+++ b/ansible/roles/cloudkitty/defaults/main.yml
@@ -122,3 +122,21 @@ cloudkitty_storage_backend: "sqlalchemy"
 # cloudkitty_influxdb_insecure_connections: false
 
 cloudkitty_influxdb_name: "cloudkitty"
+
+####################
+# Keystone
+####################
+cloudkitty_ks_services:
+  - name: "cloudkitty"
+    type: "rating"
+    description: "OpenStack Rating"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ cloudkitty_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ cloudkitty_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ cloudkitty_public_endpoint }}'}
+
+cloudkitty_ks_users:
+  - project: "service"
+    user: "{{ cloudkitty_keystone_user }}"
+    password: "{{ cloudkitty_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/cloudkitty/tasks/register.yml b/ansible/roles/cloudkitty/tasks/register.yml
index 7e487e68d6ccfb913156df7e356ab101ce36c83a..639c48cfea5cc3e792c4a6f0e1d91bcf75c93d8d 100644
--- a/ansible/roles/cloudkitty/tasks/register.yml
+++ b/ansible/roles/cloudkitty/tasks/register.yml
@@ -1,39 +1,11 @@
 ---
-- name: Creating the Cloudkitty service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "cloudkitty"
-      service_type: "rating"
-      description: "OpenStack Rating"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_cloudkitty_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ cloudkitty_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ cloudkitty_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ cloudkitty_public_endpoint }}'}
-
-- name: Creating the Cloudkitty project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ cloudkitty_keystone_user }}"
-      password: "{{ cloudkitty_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_cloudkitty_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_cloudkitty_auth }}"
+    service_ks_register_services: "{{ cloudkitty_ks_services }}"
+    service_ks_register_users: "{{ cloudkitty_ks_users }}"
+  tags: always
 
 - name: Creating the rating role
   become: true
diff --git a/ansible/roles/congress/defaults/main.yml b/ansible/roles/congress/defaults/main.yml
index 4675f656d12432308c18f3930b0348308b271b6e..fd1c0e92e5ee79b8bd15eff9ecfec4809b48e058 100644
--- a/ansible/roles/congress/defaults/main.yml
+++ b/ansible/roles/congress/defaults/main.yml
@@ -108,3 +108,21 @@ congress_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 congress_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 congress_dev_mode: "{{ kolla_dev_mode }}"
 congress_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+congress_ks_services:
+  - name: "congress"
+    type: "policy"
+    description: "Congress Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ congress_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ congress_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ congress_public_endpoint }}'}
+
+congress_ks_users:
+  - project: "service"
+    user: "{{ congress_keystone_user }}"
+    password: "{{ congress_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/congress/tasks/register.yml b/ansible/roles/congress/tasks/register.yml
index 8602471976dd55cb38d4c4501a067710ebd7c9f8..7afd6ad7c5a0ac95680079bdfa1e0ff3b6300877 100644
--- a/ansible/roles/congress/tasks/register.yml
+++ b/ansible/roles/congress/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the congress service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "congress"
-      service_type: "policy"
-      description: "Congress Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_congress_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ congress_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ congress_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ congress_public_endpoint }}'}
-
-- name: Creating the congress project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "congress"
-      password: "{{ congress_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_congress_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_congress_auth }}"
+    service_ks_register_services: "{{ congress_ks_services }}"
+    service_ks_register_users: "{{ congress_ks_users }}"
+  tags: always
diff --git a/ansible/roles/cyborg/defaults/main.yml b/ansible/roles/cyborg/defaults/main.yml
index 0da20352eddf48d649cc8a0f8d1a2e7890df909b..e6af6ae41361999e9b88742864c08d525fe1ff17 100644
--- a/ansible/roles/cyborg/defaults/main.yml
+++ b/ansible/roles/cyborg/defaults/main.yml
@@ -96,3 +96,21 @@ cyborg_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 cyborg_enabled_notification_topics: "{{ cyborg_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+cyborg_ks_services:
+  - name: "cyborg"
+    type: "cyborg"
+    description: "OpenStack Cyborg Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ cyborg_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ cyborg_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ cyborg_public_endpoint }}'}
+
+cyborg_ks_users:
+  - project: "service"
+    user: "{{ cyborg_keystone_user }}"
+    password: "{{ cyborg_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/cyborg/tasks/register.yml b/ansible/roles/cyborg/tasks/register.yml
index 88280ea156a97eadd2b4e062c82485a18169ceae..c5b54f96fa183e065dd2cbfe9639f22ecf14a8a6 100644
--- a/ansible/roles/cyborg/tasks/register.yml
+++ b/ansible/roles/cyborg/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the cyborg service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "cyborg"
-      service_type: "cyborg"
-      description: "OpenStack Cyborg Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_cyborg_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ cyborg_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ cyborg_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ cyborg_public_endpoint }}'}
-
-- name: Creating the cyborg project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ cyborg_keystone_user }}"
-      password: "{{ cyborg_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_cyborg_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_cyborg_auth }}"
+    service_ks_register_services: "{{ cyborg_ks_services }}"
+    service_ks_register_users: "{{ cyborg_ks_users }}"
+  tags: always
diff --git a/ansible/roles/designate/defaults/main.yml b/ansible/roles/designate/defaults/main.yml
index 057f7ef758ea39eae72d482f31cd612cfc93a0df..b91a13e46af4c3e7fa144d8edd45ed079d363cba 100644
--- a/ansible/roles/designate/defaults/main.yml
+++ b/ansible/roles/designate/defaults/main.yml
@@ -214,3 +214,21 @@ designate_notification_topics:
     enabled: True
 
 designate_enabled_notification_topics: "{{ designate_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+designate_ks_services:
+  - name: "designate"
+    type: "dns"
+    description: "Designate DNS Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ designate_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ designate_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ designate_public_endpoint }}'}
+
+designate_ks_users:
+  - project: "service"
+    user: "{{ designate_keystone_user }}"
+    password: "{{ designate_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/designate/tasks/register.yml b/ansible/roles/designate/tasks/register.yml
index 40f2ce4a4aa3efeae8d4a4f4b14a3c3abdb9b6c5..f73ebabba98660781cf5d0db395b0fe8f69a3dea 100644
--- a/ansible/roles/designate/tasks/register.yml
+++ b/ansible/roles/designate/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Designate service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "designate"
-      service_type: "dns"
-      description: "Designate DNS Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_designate_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ designate_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ designate_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ designate_public_endpoint }}'}
-
-- name: Creating the Designate project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ designate_keystone_user }}"
-      password: "{{ designate_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_designate_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_designate_auth }}"
+    service_ks_register_services: "{{ designate_ks_services }}"
+    service_ks_register_users: "{{ designate_ks_users }}"
+  tags: always
diff --git a/ansible/roles/freezer/defaults/main.yml b/ansible/roles/freezer/defaults/main.yml
index 4dad18d517ddede42a2f5776e931ce9c4c9c5e81..9b4cb0d9274cf0a93dcb45a071aafe0d111bebf0 100644
--- a/ansible/roles/freezer/defaults/main.yml
+++ b/ansible/roles/freezer/defaults/main.yml
@@ -96,3 +96,21 @@ freezer_api_git_repository: "{{ kolla_dev_repos_git }}/freezer-api"
 freezer_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 freezer_dev_mode: "{{ kolla_dev_mode }}"
 freezer_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+freezer_ks_services:
+  - name: "freezer"
+    type: "backup"
+    description: "Openstack Freezer Backup Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ freezer_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ freezer_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ freezer_public_endpoint }}'}
+
+freezer_ks_users:
+  - project: "service"
+    user: "{{ freezer_keystone_user }}"
+    password: "{{ freezer_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/freezer/tasks/register.yml b/ansible/roles/freezer/tasks/register.yml
index c0048f126dc3b5b1e734d45bbf5f0e781833ef77..c27427986a952f003a35c326dc5d2594abc37ea5 100644
--- a/ansible/roles/freezer/tasks/register.yml
+++ b/ansible/roles/freezer/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the freezer service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: kolla_keystone_service
-    module_args:
-      service_name: freezer
-      service_type: backup
-      description: 'Openstack Freezer Backup Service'
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_freezer_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ freezer_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ freezer_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ freezer_public_endpoint }}'}
-
-- name: Creating the freezer project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: kolla_keystone_user
-    module_args:
-      project: service
-      user: "{{ freezer_keystone_user }}"
-      password: "{{ freezer_keystone_password }}"
-      role: admin
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_freezer_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_freezer_auth }}"
+    service_ks_register_services: "{{ freezer_ks_services }}"
+    service_ks_register_users: "{{ freezer_ks_users }}"
+  tags: always
diff --git a/ansible/roles/glance/defaults/main.yml b/ansible/roles/glance/defaults/main.yml
index ead1a8fe774507b07a5b3eedb0a56f8a191c4493..1bd18accb7fe90a6b2e3470de349f1c0c82357f4 100644
--- a/ansible/roles/glance/defaults/main.yml
+++ b/ansible/roles/glance/defaults/main.yml
@@ -39,6 +39,24 @@ glance_services:
 ####################
 haproxy_members: "{% for host in glance_api_hosts %}server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ glance_api_listen_port }} check inter 2000 rise 2 fall 5;{% endfor %}"
 
+####################
+# Keystone
+####################
+glance_ks_services:
+  - name: "glance"
+    type: "image"
+    description: "Openstack Image"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ glance_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ glance_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ glance_public_endpoint }}'}
+
+glance_ks_users:
+  - project: "service"
+    user: "{{ glance_keystone_user }}"
+    password: "{{ glance_keystone_password }}"
+    role: "admin"
+
 ####################
 # Notification
 ####################
diff --git a/ansible/roles/glance/tasks/register.yml b/ansible/roles/glance/tasks/register.yml
index 43d922fff15f7a04d47e893b7d3eac7a2460daa0..7a1a715b4d13ac6d5229f2fac831393a41c4efca 100644
--- a/ansible/roles/glance/tasks/register.yml
+++ b/ansible/roles/glance/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Glance service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "glance"
-      service_type: "image"
-      description: "Openstack Image"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_glance_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ glance_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ glance_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ glance_public_endpoint }}'}
-
-- name: Creating the Glance project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ glance_keystone_user }}"
-      password: "{{ glance_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_glance_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_glance_auth }}"
+    service_ks_register_services: "{{ glance_ks_services }}"
+    service_ks_register_users: "{{ glance_ks_users }}"
+  tags: always
diff --git a/ansible/roles/gnocchi/defaults/main.yml b/ansible/roles/gnocchi/defaults/main.yml
index 4646a708d422667744835fd8a4710a1a3c9ef26f..e8ebc13501b82ef8f69fa9bc2001c09325cf4b66 100644
--- a/ansible/roles/gnocchi/defaults/main.yml
+++ b/ansible/roles/gnocchi/defaults/main.yml
@@ -132,3 +132,21 @@ gnocchi_metricd_workers: "{{ openstack_service_workers }}"
 gnocchi_keystone_user: "gnocchi"
 
 openstack_gnocchi_auth: "{{ openstack_auth }}"
+
+####################
+# Keystone
+####################
+gnocchi_ks_services:
+  - name: "gnocchi"
+    type: "metric"
+    description: "OpenStack Metric Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ gnocchi_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ gnocchi_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ gnocchi_public_endpoint }}'}
+
+gnocchi_ks_users:
+  - project: "service"
+    user: "{{ gnocchi_keystone_user }}"
+    password: "{{ gnocchi_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/gnocchi/tasks/register.yml b/ansible/roles/gnocchi/tasks/register.yml
index 417a13dc2d6061578bfe9ffac1addb31363c132a..dcfbb0344172e90165a6cd878d943e68a4b958db 100644
--- a/ansible/roles/gnocchi/tasks/register.yml
+++ b/ansible/roles/gnocchi/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the gnocchi service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "gnocchi"
-      service_type: "metric"
-      description: "OpenStack Metric Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_gnocchi_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ gnocchi_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ gnocchi_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ gnocchi_public_endpoint }}'}
-
-- name: Creating the gnocchi project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ gnocchi_keystone_user }}"
-      password: "{{ gnocchi_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_gnocchi_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_gnocchi_auth }}"
+    service_ks_register_services: "{{ gnocchi_ks_services }}"
+    service_ks_register_users: "{{ gnocchi_ks_users }}"
+  tags: always
diff --git a/ansible/roles/heat/defaults/main.yml b/ansible/roles/heat/defaults/main.yml
index 06761f170cd3e7958d9e551b1074a02c45323ba2..93d4884921f8372007246119d8334264852704ec 100644
--- a/ansible/roles/heat/defaults/main.yml
+++ b/ansible/roles/heat/defaults/main.yml
@@ -136,3 +136,28 @@ heat_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 heat_enabled_notification_topics: "{{ heat_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+heat_ks_services:
+  - name: "heat"
+    type: "orchestration"
+    description: "Orchestration"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ heat_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ heat_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ heat_public_endpoint }}'}
+  - name: "heat-cfn"
+    type: "cloudformation"
+    description: "Orchestration"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ heat_cfn_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ heat_cfn_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ heat_cfn_public_endpoint }}'}
+
+heat_ks_users:
+  - project: "service"
+    user: "{{ heat_keystone_user }}"
+    password: "{{ heat_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/heat/tasks/register.yml b/ansible/roles/heat/tasks/register.yml
index 1441b36edea4cef43cf5490d531aab54b1e478e7..abb38cc6b2bcde39ca8767ac1195faea3f764b27 100644
--- a/ansible/roles/heat/tasks/register.yml
+++ b/ansible/roles/heat/tasks/register.yml
@@ -1,42 +1,11 @@
 ---
-- name: Creating the Heat service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "{{ item.service_name }}"
-      service_type: "{{ item.service_type }}"
-      description: "{{ item.description }}"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_heat_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ heat_admin_endpoint }}', 'service_name': 'heat', 'service_type': 'orchestration', 'description': 'Orchestration'}
-    - {'interface': 'internal', 'url': '{{ heat_internal_endpoint }}', 'service_name': 'heat', 'service_type': 'orchestration', 'description': 'Orchestration'}
-    - {'interface': 'public', 'url': '{{ heat_public_endpoint }}', 'service_name': 'heat', 'service_type': 'orchestration', 'description': 'Orchestration'}
-    - {'interface': 'admin', 'url': '{{ heat_cfn_admin_endpoint }}', 'service_name': 'heat-cfn', 'service_type': 'cloudformation', 'description': 'Orchestration'}
-    - {'interface': 'internal', 'url': '{{ heat_cfn_internal_endpoint }}', 'service_name': 'heat-cfn', 'service_type': 'cloudformation', 'description': 'Orchestration'}
-    - {'interface': 'public', 'url': '{{ heat_cfn_public_endpoint }}', 'service_name': 'heat-cfn', 'service_type': 'cloudformation', 'description': 'Orchestration'}
-
-- name: Creating the Heat project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ heat_keystone_user }}"
-      password: "{{ heat_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_heat_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_heat_auth }}"
+    service_ks_register_services: "{{ heat_ks_services }}"
+    service_ks_register_users: "{{ heat_ks_users }}"
+  tags: always
 
 - name: Creating the heat_stack_user role
   become: true
diff --git a/ansible/roles/ironic/defaults/main.yml b/ansible/roles/ironic/defaults/main.yml
index 1dbdd4077e889ab24e1713a3b0e3699f9c73a884..370157c791d0c93b425654f2782e87ecdcf398e8 100644
--- a/ansible/roles/ironic/defaults/main.yml
+++ b/ansible/roles/ironic/defaults/main.yml
@@ -221,3 +221,32 @@ ironic_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 ironic_enabled_notification_topics: "{{ ironic_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+ironic_ks_services:
+  - name: "ironic"
+    type: "baremetal"
+    description: "Ironic baremetal provisioning service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ ironic_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ ironic_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ ironic_public_endpoint }}'}
+  - name: "ironic-inspector"
+    type: "baremetal-introspection"
+    description: "Ironic Inspector baremetal introspection service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ ironic_inspector_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ ironic_inspector_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ ironic_inspector_public_endpoint }}'}
+
+ironic_ks_users:
+  - project: "service"
+    user: "{{ ironic_keystone_user }}"
+    password: "{{ ironic_keystone_password }}"
+    role: "admin"
+  - project: "service"
+    user: "{{ ironic_inspector_keystone_user }}"
+    password: "{{ ironic_inspector_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/ironic/tasks/register.yml b/ansible/roles/ironic/tasks/register.yml
index 9183f8570d4e5d2632311d1cf1d6a11b0e74e051..044b267ee4b13290a876b9d56504b5c735e99a5f 100644
--- a/ansible/roles/ironic/tasks/register.yml
+++ b/ansible/roles/ironic/tasks/register.yml
@@ -1,76 +1,8 @@
 ---
-- name: Creating the Ironic service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "ironic"
-      service_type: "baremetal"
-      description: "Ironic baremetal provisioning service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_ironic_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  when: inventory_hostname in groups['ironic-api']
-  with_items:
-    - {'interface': 'admin', 'url': '{{ ironic_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ ironic_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ ironic_public_endpoint }}'}
-
-- name: Creating the Ironic project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ ironic_keystone_user }}"
-      password: "{{ ironic_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_ironic_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  when: inventory_hostname in groups['ironic-api']
-
-- name: Creating the Ironic Inspector service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "ironic-inspector"
-      service_type: "baremetal-introspection"
-      description: "Ironic Inspector baremetal introspection service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_ironic_inspector_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  when: inventory_hostname in groups['ironic-inspector']
-  with_items:
-    - {'interface': 'admin', 'url': '{{ ironic_inspector_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ ironic_inspector_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ ironic_inspector_public_endpoint }}'}
-
-- name: Creating the Ironic Inspector project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ ironic_inspector_keystone_user }}"
-      password: "{{ ironic_inspector_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_ironic_inspector_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  when: inventory_hostname in groups['ironic-inspector']
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_ironic_auth }}"
+    service_ks_register_services: "{{ ironic_ks_services }}"
+    service_ks_register_users: "{{ ironic_ks_users }}"
+  tags: always
diff --git a/ansible/roles/karbor/defaults/main.yml b/ansible/roles/karbor/defaults/main.yml
index d745fdf548c1fc92e5bcff4ccfbcc57c0d4e4e4e..83b0870daec5a06a6c7b6f7cf78f08bc4ec41b1b 100644
--- a/ansible/roles/karbor/defaults/main.yml
+++ b/ansible/roles/karbor/defaults/main.yml
@@ -106,3 +106,21 @@ karbor_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 karbor_enabled_notification_topics: "{{ karbor_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+karbor_ks_services:
+  - name: "karbor"
+    type: "data-protect"
+    description: "Application Data Protection Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ karbor_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ karbor_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ karbor_public_endpoint }}'}
+
+karbor_ks_users:
+  - project: "service"
+    user: "{{ karbor_keystone_user }}"
+    password: "{{ karbor_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/karbor/tasks/register.yml b/ansible/roles/karbor/tasks/register.yml
index d62cc2eb0d4a7fc9e8755274427af2d2213afca0..4c9e3d29197677547e33bf745415f1374ef2d353 100644
--- a/ansible/roles/karbor/tasks/register.yml
+++ b/ansible/roles/karbor/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Karbor service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "karbor"
-      service_type: "data-protect"
-      description: "Application Data Protection Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_karbor_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ karbor_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ karbor_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ karbor_public_endpoint }}'}
-
-- name: Creating the Karbor project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ karbor_keystone_user }}"
-      password: "{{ karbor_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_karbor_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_karbor_auth }}"
+    service_ks_register_services: "{{ karbor_ks_services }}"
+    service_ks_register_users: "{{ karbor_ks_users }}"
+  tags: always
diff --git a/ansible/roles/keystone/defaults/main.yml b/ansible/roles/keystone/defaults/main.yml
index db738bab0b0afd4ccdcfb6411bae198121abb037..c6ac1ad0b3ddb2a55ea499ce2a72af50204250c5 100644
--- a/ansible/roles/keystone/defaults/main.yml
+++ b/ansible/roles/keystone/defaults/main.yml
@@ -128,3 +128,16 @@ keystone_notification_topics:
     enabled: "{{ enable_barbican | bool }}"
 
 keystone_enabled_notification_topics: "{{ keystone_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+
+####################
+# Keystone
+####################
+keystone_ks_services:
+  - name: "keystone"
+    type: "identity"
+    description: "Openstack Identity Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ keystone_admin_url }}'}
+      - {'interface': 'internal', 'url': '{{ keystone_internal_url }}'}
+      - {'interface': 'public', 'url': '{{ keystone_public_url }}'}
diff --git a/ansible/roles/keystone/tasks/register.yml b/ansible/roles/keystone/tasks/register.yml
index 457e89ddfe298a2885c251d2c54e53aace55655e..69dffd94052af9110f40339997b92e69412f214a 100644
--- a/ansible/roles/keystone/tasks/register.yml
+++ b/ansible/roles/keystone/tasks/register.yml
@@ -8,28 +8,13 @@
   run_once: True
   with_items: "{{ multiple_regions_names }}"
 
-# NOTE(jeffrey4l): Since keystone-manage bootstrap cloud not update the endpoint,
-# run kolla_keystone_service module again.
-- name: Creating the Keystone service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "keystone"
-      service_type: "identity"
-      description: "Openstack Identity Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_keystone_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_keystone_auth }}"
+    service_ks_register_services: "{{ keystone_ks_services }}"
+  tags: always
   run_once: True
-  with_items:
-    - { interface: admin, url: "{{ keystone_admin_url }}" }
-    - { interface: internal, url: "{{ keystone_internal_url }}" }
-    - { interface: public, url: "{{ keystone_public_url }}" }
 
 - name: Creating default user role
   become: true
diff --git a/ansible/roles/kuryr/defaults/main.yml b/ansible/roles/kuryr/defaults/main.yml
index b16bce3c058b7eb1150db4c9a8d624de1c637d0a..b76ef0d839d88c8cbe1dd0e4860ada5aacd9a48f 100644
--- a/ansible/roles/kuryr/defaults/main.yml
+++ b/ansible/roles/kuryr/defaults/main.yml
@@ -59,3 +59,12 @@ kuryr_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 kuryr_dev_mode: "{{ kolla_dev_mode }}"
 kuryr_dimensions: "{{ default_container_dimensions }}"
 kuryr_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+kuryr_ks_users:
+  - project: "service"
+    user: "{{ kuryr_keystone_user }}"
+    password: "{{ kuryr_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/kuryr/tasks/register.yml b/ansible/roles/kuryr/tasks/register.yml
index 28b24b2e6e7caadbf80cc82bff383edd2899f968..a3b46bcef0e17a276689571e7a43119aefa5cbe9 100644
--- a/ansible/roles/kuryr/tasks/register.yml
+++ b/ansible/roles/kuryr/tasks/register.yml
@@ -1,15 +1,7 @@
 ---
-- name: Creating the Kuryr project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ kuryr_keystone_user }}"
-      password: "{{ kuryr_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_kuryr_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_kuryr_auth }}"
+    service_ks_register_users: "{{ kuryr_ks_users }}"
+  tags: always
diff --git a/ansible/roles/magnum/defaults/main.yml b/ansible/roles/magnum/defaults/main.yml
index a5a6d8f09c66f0ca4863ceda2d772dbab608db69..818c74cc661b498290f8594fb9ad8bf95b649876 100644
--- a/ansible/roles/magnum/defaults/main.yml
+++ b/ansible/roles/magnum/defaults/main.yml
@@ -115,3 +115,22 @@ magnum_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 magnum_enabled_notification_topics: "{{ magnum_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+
+####################
+# Keystone
+####################
+magnum_ks_services:
+  - name: "magnum"
+    type: "container-infra"
+    description: "Container Infrastructure Management Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ magnum_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ magnum_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ magnum_public_endpoint }}'}
+
+magnum_ks_users:
+  - project: "service"
+    user: "{{ magnum_keystone_user }}"
+    password: "{{ magnum_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/magnum/tasks/register.yml b/ansible/roles/magnum/tasks/register.yml
index 40e1a01d5d169db1555dc08bbbe990bdccfc1b65..2956bb0df4731d937be325f7fb61883d6a4e3965 100644
--- a/ansible/roles/magnum/tasks/register.yml
+++ b/ansible/roles/magnum/tasks/register.yml
@@ -1,39 +1,11 @@
 ---
-- name: Creating the Magnum service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "magnum"
-      service_type: "container-infra"
-      description: "Container Infrastructure Management Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_magnum_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ magnum_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ magnum_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ magnum_public_endpoint }}'}
-
-- name: Creating the Magnum project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ magnum_keystone_user }}"
-      password: "{{ magnum_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_magnum_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_magnum_auth }}"
+    service_ks_register_services: "{{ magnum_ks_services }}"
+    service_ks_register_users: "{{ magnum_ks_users }}"
+  tags: always
 
 - name: Creating Magnum trustee domain
   become: true
diff --git a/ansible/roles/manila/defaults/main.yml b/ansible/roles/manila/defaults/main.yml
index 03efea5040a822e1b6f145fd5c99ad37ba6fd477..a668c1f4e2c99ac41f988b39df5c3f7ba6679007 100644
--- a/ansible/roles/manila/defaults/main.yml
+++ b/ansible/roles/manila/defaults/main.yml
@@ -193,3 +193,29 @@ manila_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 manila_enabled_notification_topics: "{{ manila_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+
+####################
+# Keystone
+####################
+manila_ks_services:
+  - name: "manila"
+    type: "share"
+    description: "Openstack Shared Filesystems"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ manila_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ manila_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ manila_public_endpoint }}'}
+  - name: "manilav2"
+    type: "sharev2"
+    description: "Openstack Shared Filesystems"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ manila_v2_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ manila_v2_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ manila_v2_public_endpoint }}'}
+
+manila_ks_users:
+  - project: "service"
+    user: "{{ manila_keystone_user }}"
+    password: "{{ manila_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/manila/tasks/register.yml b/ansible/roles/manila/tasks/register.yml
index 944bb52f50137e7a12d5a545212efebc29fcec42..e3fca2540b12ecb141bd9ba7284963e80133fc44 100644
--- a/ansible/roles/manila/tasks/register.yml
+++ b/ansible/roles/manila/tasks/register.yml
@@ -1,39 +1,8 @@
 ---
-- name: Creating the Manila service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "{{ item.service_name }}"
-      service_type: "{{ item.service_type }}"
-      description: "Openstack Shared Filesystems"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_manila_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ manila_admin_endpoint }}', 'service_name': 'manila', 'service_type': 'share'}
-    - {'interface': 'internal', 'url': '{{ manila_internal_endpoint }}', 'service_name': 'manila', 'service_type': 'share'}
-    - {'interface': 'public', 'url': '{{ manila_public_endpoint }}', 'service_name': 'manila', 'service_type': 'share'}
-    - {'interface': 'admin', 'url': '{{ manila_v2_admin_endpoint }}', 'service_name': 'manilav2', 'service_type': 'sharev2'}
-    - {'interface': 'internal', 'url': '{{ manila_v2_internal_endpoint }}', 'service_name': 'manilav2', 'service_type': 'sharev2'}
-    - {'interface': 'public', 'url': '{{ manila_v2_public_endpoint }}', 'service_name': 'manilav2', 'service_type': 'sharev2'}
-
-- name: Creating the Manila project, user and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ manila_keystone_user }}"
-      password: "{{ manila_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_manila_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_manila_auth }}"
+    service_ks_register_services: "{{ manila_ks_services }}"
+    service_ks_register_users: "{{ manila_ks_users }}"
+  tags: always
diff --git a/ansible/roles/masakari/defaults/main.yml b/ansible/roles/masakari/defaults/main.yml
index 86032d0d850c1cbea364e81e894681f507e5cdff..7423749e7e1b34e98fe82d360034a0734ce16662 100644
--- a/ansible/roles/masakari/defaults/main.yml
+++ b/ansible/roles/masakari/defaults/main.yml
@@ -115,3 +115,21 @@ masakari_monitors_git_repository: "{{ kolla_dev_repos_git }}/masakarimonitors"
 masakari_monitors_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 masakari_monitors_dev_mode: "{{ kolla_dev_mode }}"
 masakari_monitors_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+masakari_ks_services:
+  - name: "masakari"
+    type: "instance-ha"
+    description: "OpenStack High Availability"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ masakari_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ masakari_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ masakari_public_endpoint }}'}
+
+masakari_ks_users:
+  - project: "service"
+    user: "{{ masakari_keystone_user }}"
+    password: "{{ masakari_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/masakari/tasks/register.yml b/ansible/roles/masakari/tasks/register.yml
index b74150ab5cb5d857ea78bfdfa6cb416fc1b61127..6ee986d95fb96a91d793c746dcd7669dba9d6a40 100644
--- a/ansible/roles/masakari/tasks/register.yml
+++ b/ansible/roles/masakari/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Masakari service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "masakari"
-      service_type: "instance-ha"
-      description: "OpenStack High Availability"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_masakari_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ masakari_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ masakari_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ masakari_public_endpoint }}'}
-
-- name: Creating the Masakari project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ masakari_keystone_user }}"
-      password: "{{ masakari_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_masakari_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_masakari_auth }}"
+    service_ks_register_services: "{{ masakari_ks_services }}"
+    service_ks_register_users: "{{ masakari_ks_users }}"
+  tags: always
diff --git a/ansible/roles/mistral/defaults/main.yml b/ansible/roles/mistral/defaults/main.yml
index 3bb98fbe8784860a5dfc09d33abc5542f6df70bf..b8f0dac90406a4ce0f074c077e7f0757729cf443 100644
--- a/ansible/roles/mistral/defaults/main.yml
+++ b/ansible/roles/mistral/defaults/main.yml
@@ -135,3 +135,21 @@ mistral_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 mistral_enabled_notification_topics: "{{ mistral_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+mistral_ks_services:
+  - name: "mistral"
+    type: "workflowv2"
+    description: "Openstack Workflow"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ mistral_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ mistral_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ mistral_public_endpoint }}'}
+
+mistral_ks_users:
+  - project: "service"
+    user: "{{ mistral_keystone_user }}"
+    password: "{{ mistral_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/mistral/tasks/register.yml b/ansible/roles/mistral/tasks/register.yml
index 8f3217dbc1fd05fcb4007ea29dfe13092355bc73..76f1640aab420266757c5c5c919e6377a08590f8 100644
--- a/ansible/roles/mistral/tasks/register.yml
+++ b/ansible/roles/mistral/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Mistral service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "mistral"
-      service_type: "workflowv2"
-      description: "Openstack Workflow"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_mistral_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ mistral_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ mistral_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ mistral_public_endpoint }}'}
-
-- name: Creating the Mistral project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ mistral_keystone_user }}"
-      password: "{{ mistral_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_mistral_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_mistral_auth }}"
+    service_ks_register_services: "{{ mistral_ks_services }}"
+    service_ks_register_users: "{{ mistral_ks_users }}"
+  tags: always
diff --git a/ansible/roles/monasca/defaults/main.yml b/ansible/roles/monasca/defaults/main.yml
index 8cef9218359c19a2803607b70a2042bb6c1f1cc8..2fafe8dbed25f7651c905918da95ac7d081fb851 100644
--- a/ansible/roles/monasca/defaults/main.yml
+++ b/ansible/roles/monasca/defaults/main.yml
@@ -338,3 +338,32 @@ monasca_log_api_internal_endpoint: "{{ internal_protocol }}://{{ kolla_internal_
 monasca_log_api_public_endpoint: "{{ public_protocol }}://{{ kolla_external_fqdn }}:{{ monasca_log_api_port }}"
 
 monasca_logging_debug: "{{ openstack_logging_debug }}"
+
+####################
+# Keystone
+####################
+monasca_ks_services:
+  - name: "monasca-api"
+    type: "monitoring"
+    description: "Monasca monitoring as a service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ monasca_api_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ monasca_api_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ monasca_api_public_endpoint }}'}
+  - name: "monasca-log-api"
+    type: "logging"
+    description: "Monasca logging as a service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ monasca_log_api_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ monasca_log_api_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ monasca_log_api_public_endpoint }}'}
+
+monasca_ks_users:
+  - project: "service"
+    user: "{{ monasca_keystone_user }}"
+    password: "{{ monasca_keystone_password }}"
+    role: "admin"
+  - project: "{{ monasca_control_plane_project }}"
+    user: "{{ monasca_agent_user }}"
+    password: "{{ monasca_agent_password }}"
+    role: "{{ monasca_agent_authorized_roles | first }}"
diff --git a/ansible/roles/monasca/tasks/register.yml b/ansible/roles/monasca/tasks/register.yml
index f6db499ddd774159d5f14248b28ec7145578c3f7..538f5ca26ecbab285e08d8bf2f8a89694d0cf3ba 100644
--- a/ansible/roles/monasca/tasks/register.yml
+++ b/ansible/roles/monasca/tasks/register.yml
@@ -1,60 +1,12 @@
 ---
-- name: Creating monasca-api service and endpoints
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "monasca-api"
-      service_type: "monitoring"
-      description: "Monasca monitoring as a service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ monasca_openstack_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ monasca_api_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ monasca_api_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ monasca_api_public_endpoint }}'}
-
-- name: Creating monasca-log-api service and endpoints
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "monasca-log-api"
-      service_type: "logging"
-      description: "Monasca logging as a service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ monasca_openstack_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ monasca_log_api_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ monasca_log_api_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ monasca_log_api_public_endpoint }}'}
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ monasca_openstack_auth }}"
+    service_ks_register_services: "{{ monasca_ks_services }}"
+    service_ks_register_users: "{{ monasca_ks_users }}"
+  tags: always
 
-- name: Creating the monasca keystone user
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ monasca_keystone_user }}"
-      password: "{{ monasca_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ monasca_openstack_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
 
 - name: Creating monasca roles
   become: true
@@ -72,18 +24,3 @@
     - "{{ monasca_agent_authorized_roles }}"
     - "{{ monasca_read_only_authorized_roles }}"
     - "{{ monasca_delegate_authorized_roles }}"
-
-- name: Creating the monasca agent user
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "{{ monasca_control_plane_project }}"
-      user: "{{ monasca_agent_user }}"
-      password: "{{ monasca_agent_password }}"
-      role: "{{ monasca_agent_authorized_roles | first }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ monasca_openstack_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
diff --git a/ansible/roles/murano/defaults/main.yml b/ansible/roles/murano/defaults/main.yml
index f19a5c74e33dc9d1412fec8576f3d7d1f4af8cc9..11ad0d1ac4d82ee27fcc2708cb98cd977716627c 100644
--- a/ansible/roles/murano/defaults/main.yml
+++ b/ansible/roles/murano/defaults/main.yml
@@ -98,3 +98,21 @@ murano_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 murano_enabled_notification_topics: "{{ murano_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+murano_ks_services:
+  - name: "murano"
+    type: "application-catalog"
+    description: "Openstack Application Catalogue"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ murano_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ murano_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ murano_public_endpoint }}'}
+
+murano_ks_users:
+  - project: "service"
+    user: "{{ murano_keystone_user }}"
+    password: "{{ murano_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/murano/tasks/register.yml b/ansible/roles/murano/tasks/register.yml
index 2068a1843c828c124fac5e2330bf683dc86feffb..f27831dc214c2a6c4fcaaf0a27c570976f7caae3 100644
--- a/ansible/roles/murano/tasks/register.yml
+++ b/ansible/roles/murano/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Murano service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "murano"
-      service_type: "application-catalog"
-      description: "Openstack Application Catalogue"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_murano_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ murano_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ murano_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ murano_public_endpoint }}'}
-
-- name: Creating the Murano project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ murano_keystone_user }}"
-      password: "{{ murano_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_murano_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_murano_auth }}"
+    service_ks_register_services: "{{ murano_ks_services }}"
+    service_ks_register_users: "{{ murano_ks_users }}"
+  tags: always
diff --git a/ansible/roles/neutron/defaults/main.yml b/ansible/roles/neutron/defaults/main.yml
index 6ca263b5ad6d64dde217efa19c69ed2c16afcbab..512da44a418f96685f67b16dc52456df98e6019a 100644
--- a/ansible/roles/neutron/defaults/main.yml
+++ b/ansible/roles/neutron/defaults/main.yml
@@ -488,3 +488,21 @@ neutron_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 neutron_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 neutron_dev_mode: "{{ kolla_dev_mode }}"
 neutron_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+neutron_ks_services:
+  - name: "neutron"
+    type: "network"
+    description: "Openstack Networking"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ neutron_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ neutron_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ neutron_public_endpoint }}'}
+
+neutron_ks_users:
+  - project: "service"
+    user: "{{ neutron_keystone_user }}"
+    password: "{{ neutron_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/neutron/tasks/register.yml b/ansible/roles/neutron/tasks/register.yml
index dc575d9ba536296aeed6a0ee135e8bcddf0ca502..5495698084511aeaa6d2b78fcda09c91fcb1e0ae 100644
--- a/ansible/roles/neutron/tasks/register.yml
+++ b/ansible/roles/neutron/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Neutron service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "neutron"
-      service_type: "network"
-      description: "Openstack Networking"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_neutron_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ neutron_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ neutron_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ neutron_public_endpoint }}'}
-
-- name: Creating the Neutron project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ neutron_keystone_user }}"
-      password: "{{ neutron_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_neutron_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_neutron_auth }}"
+    service_ks_register_services: "{{ neutron_ks_services }}"
+    service_ks_register_users: "{{ neutron_ks_users }}"
+  tags: always
diff --git a/ansible/roles/nova/defaults/main.yml b/ansible/roles/nova/defaults/main.yml
index b805c369343acd7173804ce747738416a891b2a4..dab5ad4453f6a23eaf0d3c5c69df85d744e52636 100644
--- a/ansible/roles/nova/defaults/main.yml
+++ b/ansible/roles/nova/defaults/main.yml
@@ -384,6 +384,31 @@ nova_services_require_nova_conf:
 # around 10 seconds, but the default is 30 to allow room for slowness.
 nova_compute_startup_delay: 30
 
+####################
+# Keystone
+####################
+nova_ks_services:
+  - name: "nova_legacy"
+    type: "compute_legacy"
+    description: "OpenStack Compute Service (Legacy 2.0)"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ nova_legacy_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ nova_legacy_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ nova_legacy_public_endpoint }}'}
+  - name: "nova"
+    type: "compute"
+    description: "OpenStack Compute Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ nova_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ nova_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ nova_public_endpoint }}'}
+
+nova_ks_users:
+  - project: "service"
+    user: "{{ nova_keystone_user }}"
+    password: "{{ nova_keystone_password }}"
+    role: "admin"
+
 ####################
 # Notification
 ####################
diff --git a/ansible/roles/nova/tasks/register.yml b/ansible/roles/nova/tasks/register.yml
index b80ff579d8560f4d256670a1824a1b3a39531ac5..a6ed79ffb12541fd4c3c4770b57d43ed8dfc3483 100644
--- a/ansible/roles/nova/tasks/register.yml
+++ b/ansible/roles/nova/tasks/register.yml
@@ -1,39 +1,8 @@
 ---
-- name: Creating the Nova service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "{{ item.name }}"
-      service_type: "{{ item.service_type }}"
-      description: "{{ item.description }}"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_nova_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'name': 'nova_legacy', 'service_type': 'compute_legacy', 'interface': 'admin', 'url': '{{ nova_legacy_admin_endpoint }}', 'description': 'OpenStack Compute Service (Legacy 2.0)'}
-    - {'name': 'nova_legacy', 'service_type': 'compute_legacy', 'interface': 'internal', 'url': '{{ nova_legacy_internal_endpoint }}', 'description': 'OpenStack Compute Service (Legacy 2.0)'}
-    - {'name': 'nova_legacy', 'service_type': 'compute_legacy', 'interface': 'public', 'url': '{{ nova_legacy_public_endpoint }}', 'description': 'OpenStack Compute Service (Legacy 2.0)'}
-    - {'name': 'nova', 'service_type': 'compute', 'interface': 'admin', 'url': '{{ nova_admin_endpoint }}', 'description': 'OpenStack Compute Service'}
-    - {'name': 'nova', 'service_type': 'compute', 'interface': 'internal', 'url': '{{ nova_internal_endpoint }}', 'description': 'OpenStack Compute Service'}
-    - {'name': 'nova', 'service_type': 'compute', 'interface': 'public', 'url': '{{ nova_public_endpoint }}', 'description': 'OpenStack Compute Service'}
-
-- name: Creating the Nova project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ nova_keystone_user }}"
-      password: "{{ nova_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_nova_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_nova_auth }}"
+    service_ks_register_services: "{{ nova_ks_services }}"
+    service_ks_register_users: "{{ nova_ks_users }}"
+  tags: always
diff --git a/ansible/roles/octavia/defaults/main.yml b/ansible/roles/octavia/defaults/main.yml
index 984f990fcac1b8656f70b2765a31751d66abcc9c..deae689dbd90f6c9c3211ea92babad5b10b8ae00 100644
--- a/ansible/roles/octavia/defaults/main.yml
+++ b/ansible/roles/octavia/defaults/main.yml
@@ -120,3 +120,21 @@ octavia_logging_debug: "{{ openstack_logging_debug }}"
 octavia_keystone_user: "octavia"
 
 openstack_octavia_auth: "{{ openstack_auth }}"
+
+####################
+# Keystone
+####################
+octavia_ks_services:
+  - name: "octavia"
+    type: "load-balancer"
+    description: "Octavia Load Balancing Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ octavia_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ octavia_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ octavia_public_endpoint }}'}
+
+octavia_ks_users:
+  - project: "service"
+    user: "{{ octavia_keystone_user }}"
+    password: "{{ octavia_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/octavia/tasks/register.yml b/ansible/roles/octavia/tasks/register.yml
index cefead8ca58c6d960ce7e30c1d24a0501dc060e5..7078006e05612ec27df40f7e2a361bf00ada6e0c 100644
--- a/ansible/roles/octavia/tasks/register.yml
+++ b/ansible/roles/octavia/tasks/register.yml
@@ -1,39 +1,11 @@
 ---
-- name: Creating the Octavia service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "octavia"
-      service_type: "load-balancer"
-      description: "Octavia Load Balancing Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_octavia_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ octavia_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ octavia_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ octavia_public_endpoint }}'}
-
-- name: Creating the Octavia project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ octavia_keystone_user }}"
-      password: "{{ octavia_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_octavia_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_octavia_auth }}"
+    service_ks_register_services: "{{ octavia_ks_services }}"
+    service_ks_register_users: "{{ octavia_ks_users }}"
+  tags: always
 
 - name: Adding octavia user into admin project
   become: true
diff --git a/ansible/roles/panko/defaults/main.yml b/ansible/roles/panko/defaults/main.yml
index fca49b54e312ee329e8a968f36b22f68fcc03a95..2716ce0b4e211d2bcfd587698706d9e74f2d6ecf 100644
--- a/ansible/roles/panko/defaults/main.yml
+++ b/ansible/roles/panko/defaults/main.yml
@@ -58,3 +58,21 @@ panko_logging_debug: "{{ openstack_logging_debug }}"
 panko_keystone_user: "panko"
 
 openstack_panko_auth: "{{ openstack_auth }}"
+
+####################
+# Keystone
+####################
+panko_ks_services:
+  - name: "panko"
+    type: "event"
+    description: "Panko Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ panko_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ panko_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ panko_public_endpoint }}'}
+
+panko_ks_users:
+  - project: "service"
+    user: "{{ panko_keystone_user }}"
+    password: "{{ panko_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/panko/tasks/register.yml b/ansible/roles/panko/tasks/register.yml
index 115bbee83550f93481808f496e95083547ec3bb2..75a881c5d00f4244b38080682e6078ab9e90ab24 100644
--- a/ansible/roles/panko/tasks/register.yml
+++ b/ansible/roles/panko/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the panko service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "panko"
-      service_type: "event"
-      description: "Panko Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_panko_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ panko_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ panko_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ panko_public_endpoint }}'}
-
-- name: Creating the panko project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ panko_keystone_user }}"
-      password: "{{ panko_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_panko_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_panko_auth }}"
+    service_ks_register_services: "{{ panko_ks_services }}"
+    service_ks_register_users: "{{ panko_ks_users }}"
+  tags: always
diff --git a/ansible/roles/placement/defaults/main.yml b/ansible/roles/placement/defaults/main.yml
index bcc583124af18034314f82165bb3a798d2e1fc0d..194661956c8cf72d6b8c1fdf2f58b20613124300 100644
--- a/ansible/roles/placement/defaults/main.yml
+++ b/ansible/roles/placement/defaults/main.yml
@@ -89,3 +89,21 @@ nova_api_database_name: "nova_api"
 nova_api_database_user: "{% if use_preconfigured_databases | bool and use_common_mariadb_user | bool %}{{ database_user }}{% else %}nova_api{% endif %}"
 nova_api_database_host: "{{ database_address }}"
 placement_database_host: "{{ database_address }}"
+
+####################
+# Keystone
+####################
+placement_ks_services:
+  - name: "placement"
+    type: "placement"
+    description: "Placement Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ placement_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ placement_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ placement_public_endpoint }}'}
+
+placement_ks_users:
+  - project: "service"
+    user: "{{ placement_keystone_user }}"
+    password: "{{ placement_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/placement/tasks/register.yml b/ansible/roles/placement/tasks/register.yml
index ab0678511c0bf2ab188e575566a5bd91d0e85c4b..b136c729d7d8b24459b06c9c54bd94ea4822b7be 100644
--- a/ansible/roles/placement/tasks/register.yml
+++ b/ansible/roles/placement/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the placement service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "{{ item.name }}"
-      service_type: "{{ item.service_type }}"
-      description: "{{ item.description }}"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_placement_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'name': 'placement', 'service_type': 'placement', 'interface': 'admin', 'url': '{{ placement_admin_endpoint }}', 'description': 'Placement Service'}
-    - {'name': 'placement', 'service_type': 'placement', 'interface': 'internal', 'url': '{{ placement_internal_endpoint }}', 'description': 'Placement Service'}
-    - {'name': 'placement', 'service_type': 'placement', 'interface': 'public', 'url': '{{ placement_public_endpoint }}', 'description': 'Placement Service'}
-
-- name: Creating the placement project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ placement_keystone_user }}"
-      password: "{{ placement_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_placement_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_placement_auth }}"
+    service_ks_register_services: "{{ placement_ks_services }}"
+    service_ks_register_users: "{{ placement_ks_users }}"
+  tags: always
diff --git a/ansible/roles/qinling/defaults/main.yml b/ansible/roles/qinling/defaults/main.yml
index dc4a673025ab0dbdd75037245a0a8b253adab9e0..bf626b6d0d42ed8ff735a7b4ddfb33804955f1d5 100644
--- a/ansible/roles/qinling/defaults/main.yml
+++ b/ansible/roles/qinling/defaults/main.yml
@@ -91,3 +91,21 @@ qinling_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 qinling_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 qinling_dev_mode: "{{ kolla_dev_mode }}"
 qinling_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+qinling_ks_services:
+  - name: "qinling"
+    type: "function-engine"
+    description: "Function Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ qinling_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ qinling_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ qinling_public_endpoint }}'}
+
+qinling_ks_users:
+  - project: "service"
+    user: "{{ qinling_keystone_user }}"
+    password: "{{ qinling_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/qinling/tasks/register.yml b/ansible/roles/qinling/tasks/register.yml
index fc2ca0428a0f5e6769eed0b42a15cbec4a973f28..661fcc79a686cc55f342f56301dd4103360dc537 100644
--- a/ansible/roles/qinling/tasks/register.yml
+++ b/ansible/roles/qinling/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Qinling service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "qinling"
-      service_type: "function-engine"
-      description: "Function Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_qinling_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ qinling_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ qinling_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ qinling_public_endpoint }}'}
-
-- name: Creating the Qinling project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ qinling_keystone_user }}"
-      password: "{{ qinling_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_qinling_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_qinling_auth }}"
+    service_ks_register_services: "{{ qinling_ks_services }}"
+    service_ks_register_users: "{{ qinling_ks_users }}"
+  tags: always
diff --git a/ansible/roles/sahara/defaults/main.yml b/ansible/roles/sahara/defaults/main.yml
index 6080e7c53d133689948fde0d8afc6022c9f7a3ad..89c094cc690e512ecfdc2b8097a1d8926f94e139 100644
--- a/ansible/roles/sahara/defaults/main.yml
+++ b/ansible/roles/sahara/defaults/main.yml
@@ -103,3 +103,21 @@ sahara_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 sahara_enabled_notification_topics: "{{ sahara_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+sahara_ks_services:
+  - name: "sahara"
+    type: "data-processing"
+    description: "Sahara Data Processing"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ sahara_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ sahara_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ sahara_public_endpoint }}'}
+
+sahara_ks_users:
+  - project: "service"
+    user: "{{ sahara_keystone_user }}"
+    password: "{{ sahara_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/sahara/tasks/register.yml b/ansible/roles/sahara/tasks/register.yml
index c4624d9f4fbd87eb7408d3419026713bc0970221..8492e9d5504b2d1ac4741f09ce860f1561c89a79 100644
--- a/ansible/roles/sahara/tasks/register.yml
+++ b/ansible/roles/sahara/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Sahara service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "sahara"
-      service_type: "data-processing"
-      description: "Sahara Data Processing"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_sahara_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ sahara_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ sahara_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ sahara_public_endpoint }}'}
-
-- name: Creating the Sahara project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ sahara_keystone_user }}"
-      password: "{{ sahara_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_sahara_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_sahara_auth }}"
+    service_ks_register_services: "{{ sahara_ks_services }}"
+    service_ks_register_users: "{{ sahara_ks_users }}"
+  tags: always
diff --git a/ansible/roles/searchlight/defaults/main.yml b/ansible/roles/searchlight/defaults/main.yml
index bb063ef7b8390c31f0e03f4e706cabe537fd35d0..cf5f62f994acf3883af01d71e62a10b8c581d0b1 100644
--- a/ansible/roles/searchlight/defaults/main.yml
+++ b/ansible/roles/searchlight/defaults/main.yml
@@ -85,3 +85,21 @@ searchlight_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 searchlight_enabled_notification_topics: "{{ searchlight_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+searchlight_ks_services:
+  - name: "searchlight"
+    type: "search"
+    description: "Openstack Index Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ searchlight_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ searchlight_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ searchlight_public_endpoint }}'}
+
+searchlight_ks_users:
+  - project: "service"
+    user: "{{ searchlight_keystone_user }}"
+    password: "{{ searchlight_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/searchlight/tasks/register.yml b/ansible/roles/searchlight/tasks/register.yml
index d227ebe138bfe22cf40aedef1e4dc1c25378d550..9613cb5ed3b0ec17ad2405362e6469c4a6c6f629 100644
--- a/ansible/roles/searchlight/tasks/register.yml
+++ b/ansible/roles/searchlight/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Searchlight service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "searchlight"
-      service_type: "search"
-      description: "Openstack Index Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_searchlight_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ searchlight_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ searchlight_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ searchlight_public_endpoint }}'}
-
-- name: Creating the Searchlight project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ searchlight_keystone_user }}"
-      password: "{{ searchlight_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_searchlight_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_searchlight_auth }}"
+    service_ks_register_services: "{{ searchlight_ks_services }}"
+    service_ks_register_users: "{{ searchlight_ks_users }}"
+  tags: always
diff --git a/ansible/roles/senlin/defaults/main.yml b/ansible/roles/senlin/defaults/main.yml
index f93b3d673fa602aead000f29c1a8f47c3d940b74..2b6d972e2f3aa7651312304163231504fea18587 100644
--- a/ansible/roles/senlin/defaults/main.yml
+++ b/ansible/roles/senlin/defaults/main.yml
@@ -101,3 +101,21 @@ senlin_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 senlin_enabled_notification_topics: "{{ senlin_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+senlin_ks_services:
+  - name: "senlin"
+    type: "clustering"
+    description: "Senlin Clustering Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ senlin_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ senlin_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ senlin_public_endpoint }}'}
+
+senlin_ks_users:
+  - project: "service"
+    user: "{{ senlin_keystone_user }}"
+    password: "{{ senlin_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/senlin/tasks/register.yml b/ansible/roles/senlin/tasks/register.yml
index 8b22b840112bb01c7adf820499ae14451cabc5e5..21267ea342b94b535b7c2f2286f86be4e98ea7f8 100644
--- a/ansible/roles/senlin/tasks/register.yml
+++ b/ansible/roles/senlin/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Senlin service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "senlin"
-      service_type: "clustering"
-      description: "Senlin Clustering Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_senlin_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ senlin_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ senlin_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ senlin_public_endpoint }}'}
-
-- name: Creating the Senlin project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ senlin_keystone_user }}"
-      password: "{{ senlin_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_senlin_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_senlin_auth }}"
+    service_ks_register_services: "{{ senlin_ks_services }}"
+    service_ks_register_users: "{{ senlin_ks_users }}"
+  tags: always
diff --git a/ansible/roles/service-ks-register/defaults/main.yml b/ansible/roles/service-ks-register/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c576091a6c3b6b37638f4eee3d23a053c264fcb9
--- /dev/null
+++ b/ansible/roles/service-ks-register/defaults/main.yml
@@ -0,0 +1,14 @@
+---
+service_ks_register_region_name: "{{ openstack_region_name }}"
+service_ks_register_auth: {}
+service_ks_cacert: "{{ openstack_cacert }}"
+service_ks_register_interface: "{{ openstack_interface }}"
+service_ks_register_endpoint_region: "{{ openstack_region_name }}"
+service_ks_register_domain: "default"
+service_ks_register_delegate_host: "{{ groups['control'][0] }}"
+# A list of services to register with Keystone. Each service definition should
+# provide a description, service type, and a list of associated endpoints to be
+# registered.
+service_ks_register_services: []
+# A list of users and associated roles for this service to register with Keystone
+service_ks_register_users: []
diff --git a/ansible/roles/service-ks-register/tasks/main.yml b/ansible/roles/service-ks-register/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a11da103ae1b054eab1ed1775a76b109c4413992
--- /dev/null
+++ b/ansible/roles/service-ks-register/tasks/main.yml
@@ -0,0 +1,107 @@
+---
+- name: Creating the {{ project_name }} service
+  become: true
+  kolla_toolbox:
+    module_name: "os_keystone_service"
+    module_args:
+      name: "{{ item.name }}"
+      service_type: "{{ item.type }}"
+      description: "{{ item.description }}"
+      region_name: "{{ service_ks_register_region_name }}"
+      auth: "{{ service_ks_register_auth }}"
+      interface: "{{ service_ks_register_interface }}"
+      cacert: "{{ service_ks_cacert }}"
+  run_once: True
+  loop: "{{ service_ks_register_services }}"
+  delegate_to: "{{ service_ks_register_delegate_host }}"
+
+- name: Creating the {{ project_name }} endpoints
+  become: true
+  kolla_toolbox:
+    module_name: "os_keystone_endpoint"
+    module_args:
+      service: "{{ item.0.name }}"
+      url: "{{ item.1.url }}"
+      endpoint_interface: "{{ item.1.interface }}"
+      region: "{{ service_ks_register_endpoint_region }}"
+      region_name: "{{ service_ks_register_region_name }}"
+      auth: "{{ service_ks_register_auth }}"
+      interface: "{{ service_ks_register_interface }}"
+      cacert: "{{ service_ks_cacert }}"
+  run_once: True
+  with_subelements:
+    - "{{ service_ks_register_services }}"
+    - endpoints
+  delegate_to: "{{ service_ks_register_delegate_host }}"
+
+- name: Creating the {{ project_name }} service project
+  become: true
+  kolla_toolbox:
+    module_name: "os_project"
+    module_args:
+      name: "{{ item }}"
+      domain: "{{ service_ks_register_domain }}"
+      region_name: "{{ service_ks_register_region_name }}"
+      auth: "{{ service_ks_register_auth }}"
+      interface: "{{ service_ks_register_interface }}"
+      cacert: "{{ service_ks_cacert }}"
+  run_once: True
+  with_items: "{{ service_ks_register_users | map(attribute='project') | unique | list }}"
+  delegate_to: "{{ service_ks_register_delegate_host }}"
+
+- name: Creating the {{ project_name }} service users
+  become: true
+  kolla_toolbox:
+    module_name: "os_user"
+    module_args:
+      default_project: "{{ item.project }}"
+      name: "{{ item.user }}"
+      password: "{{ item.password }}"
+      domain: "{{ service_ks_register_domain }}"
+      region_name: "{{ service_ks_register_region_name }}"
+      auth: "{{ service_ks_register_auth }}"
+      interface: "{{ service_ks_register_interface }}"
+      cacert: "{{ service_ks_cacert }}"
+  run_once: True
+  with_items: "{{ service_ks_register_users }}"
+  delegate_to: "{{ service_ks_register_delegate_host }}"
+  loop_control:
+    label:
+      user: "{{ item.user }}"
+      project: "{{ item.project }}"
+
+- name: Creating the {{ project_name }} service roles
+  become: true
+  kolla_toolbox:
+    module_name: "os_keystone_role"
+    module_args:
+      name: "{{ item }}"
+      region_name: "{{ service_ks_register_region_name }}"
+      auth: "{{ service_ks_register_auth }}"
+      interface: "{{ service_ks_register_interface }}"
+      cacert: "{{ service_ks_cacert }}"
+  run_once: True
+  with_items: "{{ service_ks_register_users | map(attribute='role') | unique | list }}"
+  delegate_to: "{{ service_ks_register_delegate_host }}"
+
+- name: Granting the {{ project_name }} service user roles
+  become: true
+  kolla_toolbox:
+    module_name: "os_user_role"
+    module_args:
+      user: "{{ item.user }}"
+      role: "{{ item.role }}"
+      project: "{{ item.project }}"
+      domain: "{{ service_ks_register_domain }}"
+      region_name: "{{ service_ks_register_region_name }}"
+      auth: "{{ service_ks_register_auth }}"
+      interface: "{{ service_ks_register_interface }}"
+      cacert: "{{ service_ks_cacert }}"
+  run_once: True
+  with_items: "{{ service_ks_register_users }}"
+  delegate_to: "{{ service_ks_register_delegate_host }}"
+  loop_control:
+    label:
+      user: "{{ item.user }}"
+      role: "{{ item.role }}"
+      project: "{{ item.project }}"
diff --git a/ansible/roles/solum/defaults/main.yml b/ansible/roles/solum/defaults/main.yml
index 6bbb337a28ebcbbae8a2bbb0a98ecb10c43f49ae..a74a82e1359e0a7095110406ee76d6a04ca6e4db 100644
--- a/ansible/roles/solum/defaults/main.yml
+++ b/ansible/roles/solum/defaults/main.yml
@@ -143,3 +143,28 @@ solum_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 solum_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 solum_dev_mode: "{{ kolla_dev_mode }}"
 solum_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+solum_ks_services:
+  - name: "solum_image_builder"
+    type: "image_builder"
+    description: "Openstack Solum Image Builder"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ solum_image_builder_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ solum_image_builder_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ solum_image_builder_public_endpoint }}'}
+  - name: "solum_application_deployment"
+    type: "application_deployment"
+    description: "Openstack Solum Application Deployment"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ solum_application_deployment_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ solum_application_deployment_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ solum_application_deployment_public_endpoint }}'}
+
+solum_ks_users:
+  - project: "service"
+    user: "{{ solum_keystone_user }}"
+    password: "{{ solum_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/solum/tasks/register.yml b/ansible/roles/solum/tasks/register.yml
index 9ed1bb5039c04af62db01d200ffadf848acd42e9..3fd4b0f7e38c144eb7ad7e233bd93999a4549501 100644
--- a/ansible/roles/solum/tasks/register.yml
+++ b/ansible/roles/solum/tasks/register.yml
@@ -1,57 +1,8 @@
 ---
-- name: Creating the Solum image builder service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "solum_image_builder"
-      service_type: "image_builder"
-      description: "Openstack Solum Image Builder"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_solum_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ solum_image_builder_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ solum_image_builder_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ solum_image_builder_public_endpoint }}'}
-
-- name: Creating the Solum application deployment service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "solum_application_deployment"
-      service_type: "application_deployment"
-      description: "Openstack Solum Application Deployment"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_solum_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ solum_application_deployment_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ solum_application_deployment_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ solum_application_deployment_public_endpoint }}'}
-
-- name: Creating the Solum project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ solum_keystone_user }}"
-      password: "{{ solum_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_solum_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_solum_auth }}"
+    service_ks_register_services: "{{ solum_ks_services }}"
+    service_ks_register_users: "{{ solum_ks_users }}"
+  tags: always
diff --git a/ansible/roles/swift/defaults/main.yml b/ansible/roles/swift/defaults/main.yml
index 427dd1d52a3b3ef1119d02c4b15e2bcd6c95f1a1..96ab2093e5389ff5d60c9abad5bd7b738c37a0ff 100644
--- a/ansible/roles/swift/defaults/main.yml
+++ b/ansible/roles/swift/defaults/main.yml
@@ -77,3 +77,21 @@ syslog_server: "{{ api_interface_address }}"
 syslog_swift_facility: "local0"
 
 swift_enable_rolling_upgrade: "yes"
+
+####################
+# Keystone
+####################
+swift_ks_services:
+  - name: "swift"
+    type: "object-store"
+    description: "Openstack Object Storage"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ swift_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ swift_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ swift_public_endpoint }}'}
+
+swift_ks_users:
+  - project: "service"
+    user: "{{ swift_keystone_user }}"
+    password: "{{ swift_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/swift/tasks/register.yml b/ansible/roles/swift/tasks/register.yml
index b6c709cb5373cfec5a91d552ba0896d77a3cbad4..e17de92986d578e93f1f2a6a7f7cb1c33e123909 100644
--- a/ansible/roles/swift/tasks/register.yml
+++ b/ansible/roles/swift/tasks/register.yml
@@ -1,39 +1,11 @@
 ---
-- name: Creating the Swift service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "swift"
-      service_type: "object-store"
-      description: "Openstack Object Storage"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_swift_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ swift_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ swift_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ swift_public_endpoint }}'}
-
-- name: Creating the Swift project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ swift_keystone_user }}"
-      password: "{{ swift_keystone_password }}"
-      role: "{{ swift_admin_tenant_name }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_swift_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_swift_auth }}"
+    service_ks_register_services: "{{ swift_ks_services }}"
+    service_ks_register_users: "{{ swift_ks_users }}"
+  tags: always
 
 - name: Creating the ResellerAdmin role
   become: true
diff --git a/ansible/roles/tacker/defaults/main.yml b/ansible/roles/tacker/defaults/main.yml
index d1e2d79d909fe7115c15cd3314b376defb55615c..4341145f1ececf6c795664210269280fd1a773ee 100644
--- a/ansible/roles/tacker/defaults/main.yml
+++ b/ansible/roles/tacker/defaults/main.yml
@@ -96,3 +96,21 @@ tacker_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 tacker_enabled_notification_topics: "{{ tacker_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+tacker_ks_services:
+  - name: "tacker"
+    type: "nfv-orchestration"
+    description: "Tacker Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ tacker_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ tacker_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ tacker_public_endpoint }}'}
+
+tacker_ks_users:
+  - project: "service"
+    user: "{{ tacker_keystone_user }}"
+    password: "{{ tacker_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/tacker/tasks/register.yml b/ansible/roles/tacker/tasks/register.yml
index f8336d11bbaed853f6c3ca29c24969ef8268c60d..8ae3eb36c2962dda6fc27afa8ce063f8e0e0a68d 100644
--- a/ansible/roles/tacker/tasks/register.yml
+++ b/ansible/roles/tacker/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Tacker service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "tacker"
-      service_type: "nfv-orchestration"
-      description: "Tacker Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_tacker_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ tacker_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ tacker_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ tacker_public_endpoint }}'}
-
-- name: Creating the Tacker project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ tacker_keystone_user }}"
-      password: "{{ tacker_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_tacker_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_tacker_auth }}"
+    service_ks_register_services: "{{ tacker_ks_services }}"
+    service_ks_register_users: "{{ tacker_ks_users }}"
+  tags: always
diff --git a/ansible/roles/trove/defaults/main.yml b/ansible/roles/trove/defaults/main.yml
index 5211cd7393ba75b75328746d20a546c64932fe7c..4e001d9e4ea223ca11b50bd04fe83457c7c05de4 100644
--- a/ansible/roles/trove/defaults/main.yml
+++ b/ansible/roles/trove/defaults/main.yml
@@ -120,3 +120,21 @@ trove_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 trove_enabled_notification_topics: "{{ trove_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+trove_ks_services:
+  - name: "trove"
+    type: "database"
+    description: "Trove Database Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ trove_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ trove_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ trove_public_endpoint }}'}
+
+trove_ks_users:
+  - project: "service"
+    user: "{{ trove_keystone_user }}"
+    password: "{{ trove_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/trove/tasks/register.yml b/ansible/roles/trove/tasks/register.yml
index 996e0c7529acdc92fc719ab086903e18303903a0..21d8b6d67d9c7a0c97a378bacdd8549aa9fcadc2 100644
--- a/ansible/roles/trove/tasks/register.yml
+++ b/ansible/roles/trove/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Trove service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "trove"
-      service_type: "database"
-      description: "Trove Database Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_trove_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ trove_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ trove_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ trove_public_endpoint }}'}
-
-- name: Creating the Trove project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ trove_keystone_user }}"
-      password: "{{ trove_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_trove_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_trove_auth }}"
+    service_ks_register_services: "{{ trove_ks_services }}"
+    service_ks_register_users: "{{ trove_ks_users }}"
+  tags: always
diff --git a/ansible/roles/vitrage/defaults/main.yml b/ansible/roles/vitrage/defaults/main.yml
index 3dd012f197102dc37460d186ed17d1b9e0cf1ff4..423ef1226b4e878956dc8eee80668254167be6ba 100644
--- a/ansible/roles/vitrage/defaults/main.yml
+++ b/ansible/roles/vitrage/defaults/main.yml
@@ -171,3 +171,21 @@ vitrage_notification_topics:
     enabled: True
 
 vitrage_enabled_notification_topics: "{{ vitrage_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+vitrage_ks_services:
+  - name: "vitrage"
+    type: "rca"
+    description: "Root Cause Analysis Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ vitrage_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ vitrage_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ vitrage_public_endpoint }}'}
+
+vitrage_ks_users:
+  - project: "service"
+    user: "{{ vitrage_keystone_user }}"
+    password: "{{ vitrage_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/vitrage/tasks/register.yml b/ansible/roles/vitrage/tasks/register.yml
index 53afab62ad027dcbd92b1966a9922d898adfc41f..936e8c6c0f7902cab39c2cbf5cdeb929a4796585 100644
--- a/ansible/roles/vitrage/tasks/register.yml
+++ b/ansible/roles/vitrage/tasks/register.yml
@@ -1,39 +1,11 @@
 ---
-- name: Creating the Vitrage service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "vitrage"
-      service_type: "rca"
-      description: "Root Cause Analysis Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_vitrage_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ vitrage_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ vitrage_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ vitrage_public_endpoint }}'}
-
-- name: Creating the Vitrage project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ vitrage_keystone_user }}"
-      password: "{{ vitrage_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_vitrage_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_vitrage_auth }}"
+    service_ks_register_services: "{{ vitrage_ks_services }}"
+    service_ks_register_users: "{{ vitrage_ks_users }}"
+  tags: always
 
 - name: Adding vitrage user into admin project
   become: true
diff --git a/ansible/roles/watcher/defaults/main.yml b/ansible/roles/watcher/defaults/main.yml
index 5a764739b0183568a0b5db7077b4f2b4a960d4be..9e4db9844ea62fa0ac255180446026ad560b5544 100644
--- a/ansible/roles/watcher/defaults/main.yml
+++ b/ansible/roles/watcher/defaults/main.yml
@@ -118,3 +118,21 @@ watcher_notification_topics:
     enabled: "{{ enable_ceilometer | bool }}"
 
 watcher_enabled_notification_topics: "{{ watcher_notification_topics | selectattr('enabled', 'equalto', true) | list }}"
+
+####################
+# Keystone
+####################
+watcher_ks_services:
+  - name: "watcher"
+    type: "infra-optim"
+    description: "Infrastructure Optimization service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ watcher_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ watcher_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ watcher_public_endpoint }}'}
+
+watcher_ks_users:
+  - project: "service"
+    user: "{{ watcher_keystone_user }}"
+    password: "{{ watcher_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/watcher/tasks/register.yml b/ansible/roles/watcher/tasks/register.yml
index 619aab4514018924635d7f9301e78328b69429d6..be1fe0c113c01b369fd0e2982ef2e295ec977684 100644
--- a/ansible/roles/watcher/tasks/register.yml
+++ b/ansible/roles/watcher/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Watcher service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "watcher"
-      service_type: "infra-optim"
-      description: "Infrastructure Optimization service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_watcher_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ watcher_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ watcher_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ watcher_public_endpoint }}'}
-
-- name: Creating the Watcher project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ watcher_keystone_user }}"
-      password: "{{ watcher_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_watcher_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_watcher_auth }}"
+    service_ks_register_services: "{{ watcher_ks_services }}"
+    service_ks_register_users: "{{ watcher_ks_users }}"
+  tags: always
diff --git a/ansible/roles/zun/defaults/main.yml b/ansible/roles/zun/defaults/main.yml
index 4ed55c6bb3e1b16161846a7f5b40f752867aa0eb..3a4a62b6e5c90a63e84b9cd7248b6d2098673a69 100644
--- a/ansible/roles/zun/defaults/main.yml
+++ b/ansible/roles/zun/defaults/main.yml
@@ -122,3 +122,21 @@ zun_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
 zun_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
 zun_dev_mode: "{{ kolla_dev_mode }}"
 zun_source_version: "{{ kolla_source_version }}"
+
+####################
+# Keystone
+####################
+zun_ks_services:
+  - name: "zun"
+    type: "container"
+    description: "Container Service"
+    endpoints:
+      - {'interface': 'admin', 'url': '{{ zun_admin_endpoint }}'}
+      - {'interface': 'internal', 'url': '{{ zun_internal_endpoint }}'}
+      - {'interface': 'public', 'url': '{{ zun_public_endpoint }}'}
+
+zun_ks_users:
+  - project: "service"
+    user: "{{ zun_keystone_user }}"
+    password: "{{ zun_keystone_password }}"
+    role: "admin"
diff --git a/ansible/roles/zun/tasks/register.yml b/ansible/roles/zun/tasks/register.yml
index c5d402b38f2ad1635f1bbc8db4423cb5bbeb63a2..207ce21da7df919ae9a70e2c48a206645f6e8d6e 100644
--- a/ansible/roles/zun/tasks/register.yml
+++ b/ansible/roles/zun/tasks/register.yml
@@ -1,36 +1,8 @@
 ---
-- name: Creating the Zun service and endpoint
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_service"
-    module_args:
-      service_name: "zun"
-      service_type: "container"
-      description: "Container Service"
-      endpoint_region: "{{ openstack_region_name }}"
-      url: "{{ item.url }}"
-      interface: "{{ item.interface }}"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_zun_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
-  with_items:
-    - {'interface': 'admin', 'url': '{{ zun_admin_endpoint }}'}
-    - {'interface': 'internal', 'url': '{{ zun_internal_endpoint }}'}
-    - {'interface': 'public', 'url': '{{ zun_public_endpoint }}'}
-
-- name: Creating the Zun project, user, and role
-  become: true
-  kolla_toolbox:
-    module_name: "kolla_keystone_user"
-    module_args:
-      project: "service"
-      user: "{{ zun_keystone_user }}"
-      password: "{{ zun_keystone_password }}"
-      role: "admin"
-      region_name: "{{ openstack_region_name }}"
-      auth: "{{ openstack_zun_auth }}"
-      endpoint_type: "{{ openstack_interface }}"
-      cacert: "{{ openstack_cacert }}"
-  run_once: True
+- import_role:
+    name: service-ks-register
+  vars:
+    service_ks_register_auth: "{{ openstack_zun_auth }}"
+    service_ks_register_services: "{{ zun_ks_services }}"
+    service_ks_register_users: "{{ zun_ks_users }}"
+  tags: always