diff --git a/ansible/roles/elasticsearch/tasks/upgrade.yml b/ansible/roles/elasticsearch/tasks/upgrade.yml
index 46601cbb8dd9e57fea8242969ebaef6344d66a4f..a15ca5026e327570f5282a26b44b9c01a8f0c019 100644
--- a/ansible/roles/elasticsearch/tasks/upgrade.yml
+++ b/ansible/roles/elasticsearch/tasks/upgrade.yml
@@ -2,23 +2,29 @@
 # The official procedure for upgrade elasticsearch:
 # https://www.elastic.co/guide/en/elasticsearch/reference/5.6/restart-upgrade.html
 - name: Disable shard allocation
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/_cluster/settings"
-    method: PUT
-    status_code: 200
-    return_content: yes
-    body: {"transient": {"cluster.routing.allocation.enable": "none"}}
-    body_format: json
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/_cluster/settings"
+      method: PUT
+      status_code: 200
+      return_content: yes
+      body: {"transient": {"cluster.routing.allocation.enable": "none"}}
+      body_format: json
   delegate_to: "{{ groups['elasticsearch'][0] }}"
   run_once: true
 
 - name: Perform a synced flush
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/_flush/synced"
-    method: POST
-    status_code: 200
-    return_content: yes
-    body_format: json
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/_flush/synced"
+      method: POST
+      status_code: 200
+      return_content: yes
+      body_format: json
   delegate_to: "{{ groups['elasticsearch'][0] }}"
   run_once: true
   retries: 10
diff --git a/ansible/roles/grafana/tasks/post_config.yml b/ansible/roles/grafana/tasks/post_config.yml
index 07385f52342d09d8b21aa31c04cfafa45a78b8a0..60add9ec6f1da2ecdb22d3a347ac8d6fed65b10f 100644
--- a/ansible/roles/grafana/tasks/post_config.yml
+++ b/ansible/roles/grafana/tasks/post_config.yml
@@ -1,8 +1,11 @@
 ---
 - name: Wait for grafana application ready
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ grafana_server_port }}/login"
-    status_code: 200
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ grafana_server_port }}/login"
+      status_code: 200
   register: result
   until: result.get('status') == 200
   retries: 30
@@ -10,15 +13,18 @@
   run_once: true
 
 - name: Enable grafana datasources
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ grafana_server_port }}/api/datasources"
-    method: POST
-    user: "{{ grafana_admin_username }}"
-    password: "{{ grafana_admin_password }}"
-    body: "{{ item.value.data | to_json }}"
-    body_format: json
-    force_basic_auth: yes
-    status_code: 200, 409
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ grafana_server_port }}/api/datasources"
+      method: POST
+      user: "{{ grafana_admin_username }}"
+      password: "{{ grafana_admin_password }}"
+      body: "{{ item.value.data | to_json }}"
+      body_format: json
+      force_basic_auth: yes
+      status_code: 200, 409
   register: response
   run_once: True
   changed_when: response.status == 200
@@ -28,13 +34,16 @@
   when: item.value.enabled | bool
 
 - name: Disable Getting Started panel
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ grafana_server_port }}/api/user/helpflags/1"
-    method: PUT
-    user: "{{ grafana_admin_username }}"
-    password: "{{ grafana_admin_password }}"
-    force_basic_auth: yes
-    status_code: 200
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ grafana_server_port }}/api/user/helpflags/1"
+      method: PUT
+      user: "{{ grafana_admin_username }}"
+      password: "{{ grafana_admin_password }}"
+      force_basic_auth: yes
+      status_code: 200
   register: grafana_response
   changed_when: grafana_response.status == 200
   run_once: true
diff --git a/ansible/roles/ironic/handlers/main.yml b/ansible/roles/ironic/handlers/main.yml
index 41478fd4f0c12091997871723e448447c1080283..458d648e1bc31bfd57b28259455e11e3b4713721 100644
--- a/ansible/roles/ironic/handlers/main.yml
+++ b/ansible/roles/ironic/handlers/main.yml
@@ -35,8 +35,11 @@
 # TODO(mgoddard): remove this task when
 # https://storyboard.openstack.org/#!/story/2006393 has been fixed.
 - name: Wait for ironic-api to be accessible
-  uri:
-    url: "{{ ironic_internal_endpoint }}"
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ ironic_internal_endpoint }}"
   register: result
   until: result is success
   retries: 12
diff --git a/ansible/roles/kibana/tasks/post_config.yml b/ansible/roles/kibana/tasks/post_config.yml
index 3f75ab223ae19cee8bdd9f1e7e5009bdd400e815..d53584f90a81cfdf43b90f2275985b99bcf0e40f 100644
--- a/ansible/roles/kibana/tasks/post_config.yml
+++ b/ansible/roles/kibana/tasks/post_config.yml
@@ -6,12 +6,15 @@
   run_once: true
 
 - name: Register the kibana index in elasticsearch
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana"
-    method: PUT
-    body: "{{ kibana_default_index_options | to_json }}"
-    body_format: json
-    status_code: 200, 201, 400
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana"
+      method: PUT
+      body: "{{ kibana_default_index_options | to_json }}"
+      body_format: json
+      status_code: 200, 201, 400
   register: result
   failed_when:
     # If the index already exists, Elasticsearch will respond with a 400 error.
@@ -21,9 +24,12 @@
   run_once: true
 
 - name: Wait for kibana to register in elasticsearch
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana"
-    status_code: 200
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana"
+      status_code: 200
   register: result
   until: result.status == 200
   retries: 20
@@ -31,21 +37,27 @@
   run_once: true
 
 - name: Change kibana config to set index as defaultIndex
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana/config/*"
-    method: PUT
-    body:
-      defaultIndex: "{{ kibana_default_index_pattern }}"
-    body_format: json
-    status_code: 200, 201
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana/config/*"
+      method: PUT
+      body:
+        defaultIndex: "{{ kibana_default_index_pattern }}"
+      body_format: json
+      status_code: 200, 201
   run_once: true
 
 - name: Get kibana default indexes
-  uri:
-    headers:
-      Content-Type: application/json
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana"
-    method: GET
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      headers:
+        Content-Type: application/json
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana"
+      method: GET
   register: kibana_default_indexes
   run_once: true
   when: kibana_default_index is defined
@@ -59,12 +71,15 @@
   connection: local
 
 - name: Add index pattern to kibana
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana/index-pattern/{{ kibana_default_index_pattern }}"  # noqa 204
-    method: PUT
-    body: "{{ kibana_default_index | to_json }}"
-    body_format: json
-    status_code: 201
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}/.kibana/index-pattern/{{ kibana_default_index_pattern }}"
+      method: PUT
+      body: "{{ kibana_default_index | to_json }}"
+      body_format: json
+      status_code: 201
   run_once: true
   when:
     - kibana_default_index is defined
diff --git a/ansible/roles/monasca/tasks/post_config.yml b/ansible/roles/monasca/tasks/post_config.yml
index 4edc8b243d0f56dadaed9be1b198209f23585ec5..de3f0170d9559e8535c7a1d7dbfbc1c4c2d7868a 100644
--- a/ansible/roles/monasca/tasks/post_config.yml
+++ b/ansible/roles/monasca/tasks/post_config.yml
@@ -1,8 +1,11 @@
 ---
 - name: Wait for Monasca Grafana to load
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/login"
-    status_code: 200
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/login"
+      status_code: 200
   register: result
   until: result.get('status') == 200
   retries: 10
@@ -14,52 +17,64 @@
     monasca_grafana_control_plane_org: "{{ monasca_control_plane_project }}@{{ default_project_domain_id }}"
 
 - name: List Monasca Grafana organisations
-  uri:
-    method: GET
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs"
-    user: '{{ monasca_grafana_admin_username }}'
-    password: '{{ monasca_grafana_admin_password }}'
-    return_content: true
-    force_basic_auth: true
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      method: GET
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs"
+      user: '{{ monasca_grafana_admin_username }}'
+      password: '{{ monasca_grafana_admin_password }}'
+      return_content: true
+      force_basic_auth: true
   run_once: True
   register: monasca_grafana_orgs
 
 - name: Create default control plane organisation if it doesn't exist
-  uri:
-    method: POST
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs"
-    user: '{{ monasca_grafana_admin_username }}'
-    password: '{{ monasca_grafana_admin_password }}'
-    body_format: json
-    body:
-      name: '{{ monasca_grafana_control_plane_org }}'
-    force_basic_auth: true
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      method: POST
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs"
+      user: '{{ monasca_grafana_admin_username }}'
+      password: '{{ monasca_grafana_admin_password }}'
+      body_format: json
+      body:
+        name: '{{ monasca_grafana_control_plane_org }}'
+      force_basic_auth: true
   run_once: True
   when: monasca_grafana_control_plane_org not in monasca_grafana_orgs.json|map(attribute='name')|unique
 
 - name: Lookup Monasca Grafana control plane organisation ID
-  uri:
-    method: GET
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs/name/{{ monasca_grafana_control_plane_org }}"
-    user: '{{ monasca_grafana_admin_username }}'
-    password: '{{ monasca_grafana_admin_password }}'
-    return_content: true
-    force_basic_auth: true
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      method: GET
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs/name/{{ monasca_grafana_control_plane_org }}"
+      user: '{{ monasca_grafana_admin_username }}'
+      password: '{{ monasca_grafana_admin_password }}'
+      return_content: true
+      force_basic_auth: true
   run_once: True
   register: monasca_grafana_conf_org
 
 - name: Add {{ monasca_grafana_admin_username }} user to control plane organisation
-  uri:
-    method: POST
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs/{{ monasca_grafana_conf_org.json.id }}/users"
-    user: '{{ monasca_grafana_admin_username }}'
-    password: '{{ monasca_grafana_admin_password }}'
-    body:
-      loginOrEmail: '{{ monasca_grafana_admin_username }}'
-      role: Admin
-    force_basic_auth: true
-    body_format: json
-    status_code: 200, 409
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      method: POST
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/orgs/{{ monasca_grafana_conf_org.json.id }}/users"
+      user: '{{ monasca_grafana_admin_username }}'
+      password: '{{ monasca_grafana_admin_password }}'
+      body:
+        loginOrEmail: '{{ monasca_grafana_admin_username }}'
+        role: Admin
+      force_basic_auth: true
+      body_format: json
+      status_code: 200, 409
   register: monasca_grafana_add_user_response
   run_once: True
   changed_when: monasca_grafana_add_user_response.status == 200
@@ -67,24 +82,30 @@
                monasca_grafana_add_user_response.status == 409 and ("User is already" not in  monasca_grafana_add_user_response.json.message|default(""))
 
 - name: Switch Monasca Grafana to the control plane organisation
-  uri:
-    method: POST
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/user/using/{{ monasca_grafana_conf_org.json.id }}"
-    user: '{{ monasca_grafana_admin_username }}'
-    password: '{{ monasca_grafana_admin_password }}'
-    force_basic_auth: true
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      method: POST
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/user/using/{{ monasca_grafana_conf_org.json.id }}"
+      user: '{{ monasca_grafana_admin_username }}'
+      password: '{{ monasca_grafana_admin_password }}'
+      force_basic_auth: true
   run_once: True
 
 - name: Enable Monasca Grafana datasource for control plane organisation
-  uri:
-    url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/datasources"
-    method: POST
-    user: "{{ monasca_grafana_admin_username }}"
-    password: "{{ monasca_grafana_admin_password }}"
-    body: "{{ item.value.data | to_json }}"
-    body_format: json
-    force_basic_auth: true
-    status_code: 200, 409
+  become: true
+  kolla_toolbox:
+    module_name: uri
+    module_args:
+      url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ monasca_grafana_server_port }}/api/datasources"
+      method: POST
+      user: "{{ monasca_grafana_admin_username }}"
+      password: "{{ monasca_grafana_admin_password }}"
+      body: "{{ item.value.data | to_json }}"
+      body_format: json
+      force_basic_auth: true
+      status_code: 200, 409
   register: monasca_grafana_datasource_response
   run_once: True
   changed_when: monasca_grafana_datasource_response.status == 200
diff --git a/releasenotes/notes/execute-rest-methods-inside-containers-ce2a1410dbdc71f3.yaml b/releasenotes/notes/execute-rest-methods-inside-containers-ce2a1410dbdc71f3.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d9b26d35f6ea5f03621306b5b4c18326def0ab17
--- /dev/null
+++ b/releasenotes/notes/execute-rest-methods-inside-containers-ce2a1410dbdc71f3.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Delegate executing ansible uri REST methods to service containers using
+    kolla_toolbox. This will enable any certificates that are already copied
+    and extracted into the service container to be automatically validated.
+    This is particularly useful in the case that the certificate is either
+    self-signed or signed by a local (private) CA.