diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index aed7db9865..7258f26d7b 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -219,6 +219,9 @@ nova_keystone_user: "nova"
 enable_nova_fake: "no"
 num_nova_fake_per_node: 5
 
+# Control usage of ceph per service
+glance_enable_ceph: "{{ enable_ceph }}"
+
 ####################
 # RabbitMQ options
 ####################
diff --git a/ansible/roles/glance/tasks/deploy.yml b/ansible/roles/glance/tasks/deploy.yml
index 450db4f932..65df10888c 100644
--- a/ansible/roles/glance/tasks/deploy.yml
+++ b/ansible/roles/glance/tasks/deploy.yml
@@ -1,10 +1,16 @@
 ---
 - include: ceph.yml
   when:
-    - enable_ceph | bool
+    - (enable_ceph | bool) and (glance_enable_ceph | bool)
     - inventory_hostname in groups['ceph-mon'] or
-        inventory_hostname in groups['glance-api'] or
-        inventory_hostname in groups['glance-registry']
+      inventory_hostname in groups['glance-api'] or
+      inventory_hostname in groups['glance-registry']
+
+- include: external_ceph.yml
+  when:
+    - (enable_ceph | bool == False) and (glance_enable_ceph | bool)
+    - inventory_hostname in groups['glance-api'] or
+      inventory_hostname in groups['glance-registry']
 
 - include: register.yml
   when: inventory_hostname in groups['glance-api']
diff --git a/ansible/roles/glance/tasks/external_ceph.yml b/ansible/roles/glance/tasks/external_ceph.yml
new file mode 100644
index 0000000000..43e9cf7205
--- /dev/null
+++ b/ansible/roles/glance/tasks/external_ceph.yml
@@ -0,0 +1,13 @@
+---
+- name: Ensuring config directory exists
+  file:
+    path: "{{ node_config_directory }}/glance-api"
+    state: "directory"
+  when: inventory_hostname in groups['glance-api']
+
+- name: Copy over ceph files
+  copy:
+    src: "{{ item }}"
+    dest: "{{ node_config_directory }}/glance-api/"
+  with_fileglob:
+    - "{{ node_custom_config }}/glance/ceph*"
diff --git a/ansible/roles/glance/templates/glance-api.conf.j2 b/ansible/roles/glance/templates/glance-api.conf.j2
index f81a7296b6..272dc0d9d3 100644
--- a/ansible/roles/glance/templates/glance-api.conf.j2
+++ b/ansible/roles/glance/templates/glance-api.conf.j2
@@ -39,7 +39,7 @@ memcached_servers = {% for host in groups['memcached'] %}{{ hostvars[host]['ansi
 flavor = keystone
 
 [glance_store]
-{% if enable_ceph | bool %}
+{% if enable_ceph | bool and glance_enable_ceph | bool %}
 default_store = rbd
 stores = rbd
 rbd_store_user = glance
diff --git a/ansible/roles/glance/templates/glance-api.json.j2 b/ansible/roles/glance/templates/glance-api.json.j2
index 755f649c3e..1afd6929ff 100644
--- a/ansible/roles/glance/templates/glance-api.json.j2
+++ b/ansible/roles/glance/templates/glance-api.json.j2
@@ -6,18 +6,13 @@
             "dest": "/etc/glance/glance-api.conf",
             "owner": "glance",
             "perm": "0600"
-        }{% if enable_ceph | bool %},
+        }{% if glance_enable_ceph | bool %},
         {
-            "source": "{{ container_config_directory }}/ceph.client.glance.keyring",
-            "dest": "/etc/ceph/ceph.client.glance.keyring",
+            "source": "{{ container_config_directory }}/ceph.*",
+            "dest": "/etc/ceph/",
             "owner": "glance",
-            "perm": "0600"
-        },
-        {
-            "source": "{{ container_config_directory }}/ceph.conf",
-            "dest": "/etc/ceph/ceph.conf",
-            "owner": "glance",
-            "perm": "0600"
-        }{% endif %}
+            "perm": "0700"
+        }
+        {% endif %}
     ]
 }
diff --git a/docker/base/set_configs.py b/docker/base/set_configs.py
index fd22a31558..94bf24a6be 100644
--- a/docker/base/set_configs.py
+++ b/docker/base/set_configs.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import argparse
+import glob
 import json
 import logging
 import os
@@ -45,15 +46,15 @@ def validate_config(config):
 def validate_source(data):
     source = data.get('source')
 
-    exists = os.path.exists(source)
-
-    if not exists:
-        if data.get('optional'):
-            LOG.info("%s does not exist, but is not required", source)
-            return False
-        else:
-            LOG.error("The source to copy does not exist: %s", source)
-            sys.exit(1)
+    # Only check existance if no wildcard found
+    if '*' not in source:
+        if not os.path.exists(source):
+            if data.get('optional'):
+                LOG.info("%s does not exist, but is not required", source)
+                return False
+            else:
+                LOG.error("The source to copy does not exist: %s", source)
+                sys.exit(1)
 
     return True
 
@@ -82,8 +83,9 @@ def copy_files(data):
 
     if source != source_path:
         # Source is file
-        LOG.info("Copying %s to %s", source, dest)
-        shutil.copy(source, dest)
+        for file in glob.glob(source):
+            LOG.info("Copying %s to %s", file, dest)
+            shutil.copy(file, dest)
     else:
         # Source is a directory
         for src in os.listdir(source_path):
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index acee827022..620fad8c5c 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -125,6 +125,9 @@ neutron_external_interface: "eth1"
 #enable_neutron_qos: "no"
 #enable_swift: "no"
 
+# Control usage of ceph per service. This allows to configure external ceph
+# when ceph is not deployed by Kolla.
+#glance_enable_ceph: "{{ enable_ceph }}"
 
 ###################
 # Ceph options