]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/volumes: Disallow authorize existing auth_id
authorKotresh HR <khiremat@redhat.com>
Mon, 4 Jan 2021 13:04:54 +0000 (18:34 +0530)
committerKotresh HR <khiremat@redhat.com>
Fri, 5 Mar 2021 06:50:31 +0000 (12:20 +0530)
This patch disallow the mgr plugin to authorize the auth_id
which is not created via mgr plugin. Those auth_ids could be
created by other means for other use cases which should not be modified
via mgr plugin.

Fixes: https://tracker.ceph.com/issues/44931
Signed-off-by: Kotresh HR <khiremat@redhat.com>
(cherry picked from commit c02890404e47a5a95c5cc16b699306045d586c7f)

src/pybind/mgr/volumes/fs/operations/access.py
src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py

index e56b416f53d696f67a206f57793cfc6c09aa050b..61585e704e990316f3321929724c74a1cdb3c5a4 100644 (file)
@@ -2,20 +2,15 @@ import errno
 import json
 
 def allow_access(mgr, client_entity, want_mds_cap, want_osd_cap,
-               unwanted_mds_cap, unwanted_osd_cap):
-    ret, out, err = mgr.mon_command({
-        "prefix": "auth get",
-        "entity": client_entity,
-        "format": "json"})
-
-    if ret == -errno.ENOENT:
+                 unwanted_mds_cap, unwanted_osd_cap, existing_caps):
+    if existing_caps is None:
         ret, out, err = mgr.mon_command({
             "prefix": "auth get-or-create",
             "entity": client_entity,
             "caps": ['mds',  want_mds_cap, 'osd', want_osd_cap, 'mon', 'allow r'],
             "format": "json"})
     else:
-        cap = json.loads(out)[0]
+        cap = existing_caps[0]
 
         def cap_update(
                 orig_mds_caps, orig_osd_caps, want_mds_cap,
index 6bb97ae6b19b9370c3bb880fce96858256251bd4..c75fd0d6ada12dcd2666d6bd71f4b03ab85c84bb 100644 (file)
@@ -267,7 +267,22 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
                 if subvol_meta['auths'][auth_id] == want_auth:
                     continue
 
-                self._authorize_subvolume(auth_id, access_level)
+                client_entity = "client.{0}".format(auth_id)
+                ret, out, err = self.mgr.mon_command(
+                    {
+                        'prefix': 'auth get',
+                        'entity': client_entity,
+                        'format': 'json'
+                    })
+                if ret == 0:
+                    existing_caps = json.loads(out)
+                elif ret == -errno.ENOENT:
+                    existing_caps = None
+                else:
+                    log.error(err)
+                    raise VolumeException(ret, err)
+
+                self._authorize_subvolume(auth_id, access_level, existing_caps)
 
             # Recovered from partial auth updates for the auth ID's access
             # to a subvolume.
@@ -299,6 +314,22 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
         """
 
         with self.auth_mdata_mgr.auth_lock(auth_id):
+            client_entity = "client.{0}".format(auth_id)
+            ret, out, err = self.mgr.mon_command(
+                {
+                    'prefix': 'auth get',
+                    'entity': client_entity,
+                    'format': 'json'
+                })
+
+            if ret == 0:
+                existing_caps = json.loads(out)
+            elif ret == -errno.ENOENT:
+                existing_caps = None
+            else:
+                log.error(err)
+                raise VolumeException(ret, err)
+
             # Existing meta, or None, to be updated
             auth_meta = self.auth_mdata_mgr.auth_metadata_get(auth_id)
 
@@ -313,7 +344,14 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
                     'dirty': True,
                 }
             }
+
             if auth_meta is None:
+                if existing_caps is not None:
+                    msg = "auth ID: {0} exists and not created by mgr plugin. Not allowed to modify".format(auth_id)
+                    log.error(msg)
+                    raise VolumeException(-errno.EPERM, msg)
+
+                # non-existent auth IDs
                 sys.stderr.write("Creating meta for ID {0} with tenant {1}\n".format(
                     auth_id, tenant_id
                 ))
@@ -323,14 +361,6 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
                     'tenant_id': str(tenant_id) if tenant_id else None,
                     'volumes': subvolume
                 }
-
-                # Note: this is *not* guaranteeing that the key doesn't already
-                # exist in Ceph: we are allowing VolumeClient tenants to
-                # 'claim' existing Ceph keys.  In order to prevent VolumeClient
-                # tenants from reading e.g. client.admin keys, you need to
-                # have configured your VolumeClient user (e.g. Manila) to
-                # have mon auth caps that prevent it from accessing those keys
-                # (e.g. limit it to only access keys with a manila.* prefix)
             else:
                 # Disallow tenants to share auth IDs
                 if str(auth_meta['tenant_id']) != str(tenant_id):
@@ -350,7 +380,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
             self.auth_mdata_mgr.auth_metadata_set(auth_id, auth_meta)
 
             with self.auth_mdata_mgr.subvol_metadata_lock(self.group.groupname, self.subvolname):
-                key = self._authorize_subvolume(auth_id, access_level)
+                key = self._authorize_subvolume(auth_id, access_level, existing_caps)
 
             auth_meta['dirty'] = False
             auth_meta['volumes'][group_subvol_id]['dirty'] = False
@@ -363,7 +393,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
                 # them a key
                 return ""
 
-    def _authorize_subvolume(self, auth_id, access_level):
+    def _authorize_subvolume(self, auth_id, access_level, existing_caps):
         subvol_meta = self.auth_mdata_mgr.subvol_metadata_get(self.group.groupname, self.subvolname)
 
         auth = {
@@ -381,14 +411,14 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
             subvol_meta['auths'].update(auth)
             self.auth_mdata_mgr.subvol_metadata_set(self.group.groupname, self.subvolname, subvol_meta)
 
-        key = self._authorize(auth_id, access_level)
+        key = self._authorize(auth_id, access_level, existing_caps)
 
         subvol_meta['auths'][auth_id]['dirty'] = False
         self.auth_mdata_mgr.subvol_metadata_set(self.group.groupname, self.subvolname, subvol_meta)
 
         return key
 
-    def _authorize(self, auth_id, access_level):
+    def _authorize(self, auth_id, access_level, existing_caps):
         subvol_path = self.path
         log.debug("Authorizing Ceph id '{0}' for path '{1}'".format(auth_id, subvol_path))
 
@@ -419,7 +449,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
                 unwanted_access_level, pool, " namespace={0}".format(namespace) if namespace else "")
 
         return allow_access(self.mgr, client_entity, want_mds_cap, want_osd_cap,
-                            unwanted_mds_cap, unwanted_osd_cap)
+                            unwanted_mds_cap, unwanted_osd_cap, existing_caps)
 
     def deauthorize(self, auth_id):
         with self.auth_mdata_mgr.auth_lock(auth_id):