diff --git a/ansible/library/kolla_ceph_keyring.py b/ansible/library/kolla_ceph_keyring.py
new file mode 100644
index 0000000000..5041563ecd
--- /dev/null
+++ b/ansible/library/kolla_ceph_keyring.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+
+# Copyright 2018 99cloud
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+import subprocess  # nosec
+
+
+DOCUMENTATION = '''
+---
+module: kolla_ceph_keyring
+short_description: >
+  Module for update ceph client keyring caps in kolla.
+description:
+  - A module used to update ceph client keyring caps in kolla.
+options:
+  name:
+    description:
+      - the client name in ceph
+    required: True
+    type: str
+  container_name:
+    description:
+      - the ceph mon container name
+    required: True
+    default: ceph_mon
+    type: str
+  caps:
+    description:
+      - the ceph auth caps
+    required: True
+    type: dict
+author: Jeffrey Zhang
+'''
+
+EXAMPLES = '''
+- name: configure admin client caps
+  kolla_ceph_keyring:
+    name: client.admin
+    container_name: ceph_mon
+    caps:
+      mds: 'allow'
+      mon: 'allow *'
+      osd: 'allow *'
+      mgr: 'allow *'
+'''
+
+
+class CephKeyring(object):
+    def __init__(self, name, caps, container_name='ceph_mon'):
+        self.name = name
+        self.caps = caps
+        self.container_name = container_name
+        self.changed = False
+        self.message = None
+
+    def _run(self, cmd):
+        _prefix = ['docker', 'exec', self.container_name]
+        cmd = _prefix + cmd
+        proc = subprocess.Popen(cmd,  # nosec
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE)
+        stdout, stderr = proc.communicate()
+        retcode = proc.poll()
+        if retcode != 0:
+            output = 'stdout: "%s", stderr: "%s"' % (stdout, stderr)
+            raise subprocess.CalledProcessError(retcode, cmd, output)
+        return stdout
+
+    def _format_caps(self):
+        caps = []
+        for obj in sorted(self.caps):
+            caps.extend([obj, self.caps[obj]])
+        return caps
+
+    def parse_stdout(self, stdout):
+        keyring = json.loads(stdout)
+        # there should be only one element
+        return keyring[0]
+
+    def ensure_keyring(self):
+        try:
+            stdout = self.get_keyring()
+        except subprocess.CalledProcessError:
+            # keyring doesn't exsit, try to create it
+            stdout = self.create_keyring()
+            self.changed = True
+            self.message = 'ceph keyring for %s is created' % self.name
+        keyring = self.parse_stdout(stdout)
+        if keyring['caps'] != self.caps:
+            self.update_caps()
+            stdout = self.get_keyring()
+            keyring = self.parse_stdout(stdout)
+            self.changed = True
+            self.message = 'ceph keyring for %s is updated' % self.name
+        self.keyring = keyring
+        return self.keyring
+
+    def get_keyring(self):
+        ceph_cmd = ['ceph', '--format', 'json', 'auth', 'get', self.name]
+        return self._run(ceph_cmd)
+
+    def update_caps(self):
+        ceph_cmd = ['ceph', '--format', 'json', 'auth', 'caps', self.name]
+        caps = self._format_caps()
+        ceph_cmd.extend(caps)
+        self._run(ceph_cmd)
+
+    def create_keyring(self):
+        ceph_cmd = ['ceph', '--format', 'json', 'auth',
+                    'get-or-create', self.name]
+        caps = self._format_caps()
+        ceph_cmd.extend(caps)
+        return self._run(ceph_cmd)
+
+
+def main():
+    specs = dict(
+        name=dict(type='str', required=True),
+        container_name=dict(type='str', default='ceph_mon'),
+        caps=dict(type='dict', required=True)
+    )
+    module = AnsibleModule(argument_spec=specs)  # noqa
+    params = module.params
+    ceph_keyring = CephKeyring(params['name'],
+                               params['caps'],
+                               params['container_name'])
+    try:
+        keyring = ceph_keyring.ensure_keyring()
+        module.exit_json(changed=ceph_keyring.changed,
+                         keyring=keyring,
+                         message=ceph_keyring.message)
+    except subprocess.CalledProcessError as ex:
+        msg = ('Failed to call command: %s returncode: %s output: %s' %
+               (ex.cmd, ex.returncode, ex.output))
+        module.fail_json(msg=msg)
+
+
+from ansible.module_utils.basic import *  # noqa
+if __name__ == "__main__":
+    main()
diff --git a/ansible/roles/ceph/defaults/main.yml b/ansible/roles/ceph/defaults/main.yml
index 0655c6724a..25713a95ee 100644
--- a/ansible/roles/ceph/defaults/main.yml
+++ b/ansible/roles/ceph/defaults/main.yml
@@ -40,6 +40,12 @@ osd_initial_weight: "1"
 # Increase tcmalloc cache size
 ceph_tcmalloc_tc_bytes: "134217728"
 
+ceph_client_admin_keyring_caps:
+  mds: "allow"
+  mon: "allow *"
+  osd: "allow *"
+  mgr: "allow *"
+
 ####################
 ## Ceph_rgw_keystone
 ####################
diff --git a/ansible/roles/ceph/tasks/deploy.yml b/ansible/roles/ceph/tasks/deploy.yml
index 39dc253203..286ca26f5c 100644
--- a/ansible/roles/ceph/tasks/deploy.yml
+++ b/ansible/roles/ceph/tasks/deploy.yml
@@ -17,6 +17,13 @@
     - enable_ceph_nfs | bool
     - inventory_hostname in groups['ceph-nfs']
 
+- name: configuring client.admin caps
+  kolla_ceph_keyring:
+    name: client.admin
+    caps: "{{ ceph_client_admin_keyring_caps }}"
+  run_once: True
+  delegate_to: "{{ groups['ceph-mon'][0] }}"
+
 - include: bootstrap_osds.yml
   when: inventory_hostname in groups['ceph-osd']
 
diff --git a/ansible/roles/ceph/tasks/upgrade.yml b/ansible/roles/ceph/tasks/upgrade.yml
index cc703e9ff0..52c2c15527 100644
--- a/ansible/roles/ceph/tasks/upgrade.yml
+++ b/ansible/roles/ceph/tasks/upgrade.yml
@@ -1,6 +1,15 @@
 ---
 - include: config.yml
 
+# NOTE(jeffrey4l): client.admin caps should be update when upgrade from Jewel
+# to Luminous
+- name: configuring client.admin caps
+  kolla_ceph_keyring:
+    name: client.admin
+    caps: "{{ ceph_client_admin_keyring_caps }}"
+  run_once: True
+  delegate_to: "{{ groups['ceph-mon'][0] }}"
+
 - include: start_mons.yml
   when: inventory_hostname in groups['ceph-mon']