]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: add MAY_SNAPSHOT in MDSAuthCaps
authorYan, Zheng <zyan@redhat.com>
Thu, 14 Jun 2018 09:21:59 +0000 (17:21 +0800)
committerYan, Zheng <zyan@redhat.com>
Tue, 19 Jun 2018 09:08:39 +0000 (17:08 +0800)
For controlling whether a client is allowed to create or delete
snapshots

Fixes: http://tracker.ceph.com/issues/24284
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
PendingReleaseNotes
doc/cephfs/client-auth.rst
src/mds/MDSAuthCaps.cc
src/mds/MDSAuthCaps.h
src/mds/Server.cc
src/mon/AuthMonitor.cc
src/test/mds/TestMDSAuthCaps.cc

index 2761c198e7f4f9333aabecbef4e6651876354999..e06be5874721665fae83d209850d776f57fcf0b9 100644 (file)
 * The JSON output of the ``osd find`` command has replaced the ``ip``
   field with an ``addrs`` section to reflect that OSDs may bind to
   multiple addresses.
+
+* CephFS clients without the 's' flag in their authentication capability
+  string will no longer be able to create/delete snapshots. To allow
+  ``client.foo`` to create/delete snapshots in the ``bar`` directory of
+  filesystem ``cephfs_a``, use command:
+
+    - ``ceph auth caps client.foo mon 'allow r' osd 'allow rw tag cephfs data=cephfs_a' mds 'allow rw, allow rws path=/bar'``
index 78dd81fe970d4f5186094fbdd777bb6865250997..851da5246e466f2448bbb97e0ef7023045bc64e3 100644 (file)
@@ -110,4 +110,23 @@ on the filesystem cephfs_a, but client.1 cannot.
         caps: [osd] allow rw tag cephfs data=cephfs_a
 
 
+Snapshot restriction (the 's' flag)
+===========================================
+
+To create or delete snapshots, clients require the 's' flag in addition to 'rw'.
+Note that when capability string also contains the 'p' flag, the 's' flag must
+appear after it (all flags except 'rw' must be specified in alphabetical order).
+
+For example, in the following snippet client.0 can create or delete snapshots
+in the ``bar`` directory of filesystem ``cephfs_a``.
+
+::
+
+    client.0
+        key: AQAz7EVWygILFRAAdIcuJ12opU/JKyfFmxhuaw==
+        caps: [mds] allow rw, allow rws path=/bar
+        caps: [mon] allow r
+        caps: [osd] allow rw tag cephfs data=cephfs_a
+
+
 .. _User Management - Add a User to a Keyring: ../../rados/operations/user-management/#add-a-user-to-a-keyring
index aeb86d8851d90c3a664f9d7478c0145cd04e4da7..13ab77ee1f91bc4985cde1d5f367e534a8bb04a2 100644 (file)
@@ -69,17 +69,21 @@ struct MDSCapParser : qi::grammar<Iterator, MDSAuthCaps()>
             (path >> uid >> gidlist)[_val = phoenix::construct<MDSCapMatch>(_1, _2, _3)] |
              (path)[_val = phoenix::construct<MDSCapMatch>(_1)]);
 
-    // capspec = * | r[w]
+    // capspec = * | r[w][p][s]
     capspec = spaces >> (
-        lit("*")[_val = MDSCapSpec(true, true, true, true)]
+        lit("*")[_val = MDSCapSpec(MDSCapSpec::ALL)]
         |
-        lit("all")[_val = MDSCapSpec(true, true, true, true)]
+        lit("all")[_val = MDSCapSpec(MDSCapSpec::ALL)]
         |
-        (lit("rwp"))[_val = MDSCapSpec(true, true, false, true)]
+        (lit("rwps"))[_val = MDSCapSpec(MDSCapSpec::RWPS)]
         |
-        (lit("rw"))[_val = MDSCapSpec(true, true, false, false)]
+        (lit("rwp"))[_val = MDSCapSpec(MDSCapSpec::RWP)]
         |
-        (lit("r"))[_val = MDSCapSpec(true, false, false, false)]
+        (lit("rws"))[_val = MDSCapSpec(MDSCapSpec::RWS)]
+        |
+        (lit("rw"))[_val = MDSCapSpec(MDSCapSpec::RW)]
+        |
+        (lit("r"))[_val = MDSCapSpec(MDSCapSpec::READ)]
         );
 
     grant = lit("allow") >> (capspec >> match)[_val = phoenix::construct<MDSCapGrant>(_1, _2)];
@@ -221,7 +225,13 @@ bool MDSAuthCaps::is_capable(std::string_view inode_path,
 
       // Spec is non-allowing if caller asked for set pool but spec forbids it
       if (mask & MAY_SET_VXATTR) {
-        if (!i->spec.allows_set_vxattr()) {
+        if (!i->spec.allow_set_vxattr()) {
+          continue;
+        }
+      }
+
+      if (mask & MAY_SNAPSHOT) {
+        if (!i->spec.allow_snapshot()) {
           continue;
         }
       }
@@ -276,9 +286,7 @@ bool MDSAuthCaps::is_capable(std::string_view inode_path,
 void MDSAuthCaps::set_allow_all()
 {
     grants.clear();
-    grants.push_back(MDSCapGrant(
-                       MDSCapSpec(true, true, true, true),
-                       MDSCapMatch()));
+    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::ALL), MDSCapMatch()));
 }
 
 bool MDSAuthCaps::parse(CephContext *c, std::string_view str, ostream *err)
@@ -286,7 +294,7 @@ bool MDSAuthCaps::parse(CephContext *c, std::string_view str, ostream *err)
   // Special case for legacy caps
   if (str == "allow") {
     grants.clear();
-    grants.push_back(MDSCapGrant(MDSCapSpec(true, true, false, true), MDSCapMatch()));
+    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::RWPS), MDSCapMatch()));
     return true;
   }
 
@@ -353,15 +361,21 @@ ostream &operator<<(ostream &out, const MDSCapMatch &match)
 
 ostream &operator<<(ostream &out, const MDSCapSpec &spec)
 {
-  if (spec.any) {
+  if (spec.allow_all()) {
     out << "*";
   } else {
-    if (spec.read) {
+    if (spec.allow_read()) {
       out << "r";
     }
-    if (spec.write) {
+    if (spec.allow_write()) {
       out << "w";
     }
+    if (spec.allow_set_vxattr()) {
+      out << "p";
+    }
+    if (spec.allow_snapshot()) {
+      out << "s";
+    }
   }
 
   return out;
index b867da4f0f9d8d633c009ef27ecba8ab429ddf26..d7c3a66ac8610144dabd75efce12e83f3642834d 100644 (file)
 
 // unix-style capabilities
 enum {
-  MAY_READ = 1,
-  MAY_WRITE = 2,
-  MAY_EXECUTE = 4,
-  MAY_CHOWN = 16,
-  MAY_CHGRP = 32,
-  MAY_SET_VXATTR = 64,
+  MAY_READ     = (1 << 0),
+  MAY_WRITE    = (1 << 1),
+  MAY_EXECUTE  = (1 << 2),
+  MAY_CHOWN    = (1 << 4),
+  MAY_CHGRP    = (1 << 5),
+  MAY_SET_VXATTR = (1 << 6),
+  MAY_SNAPSHOT = (1 << 7),
 };
 
 class CephContext;
 
 // what we can do
 struct MDSCapSpec {
-  bool read, write, any;
-
-  // True if the capability permits setting vxattrs (layout, quota, etc)
-  bool set_vxattr;
-
-  MDSCapSpec() : read(false), write(false), any(false), set_vxattr(false) {}
-  MDSCapSpec(bool r, bool w, bool a, bool lop)
-    : read(r), write(w), any(a), set_vxattr(lop) {}
+  static const unsigned ALL            = (1 << 0);
+  static const unsigned READ           = (1 << 1);
+  static const unsigned WRITE          = (1 << 2);
+  // if the capability permits setting vxattrs (layout, quota, etc)
+  static const unsigned SET_VXATTR     = (1 << 3);
+  // if the capability permits mksnap/rmsnap
+  static const unsigned SNAPSHOT       = (1 << 4);
+
+  static const unsigned RW             = (READ|WRITE);
+  static const unsigned RWP            = (READ|WRITE|SET_VXATTR);
+  static const unsigned RWS            = (READ|WRITE|SNAPSHOT);
+  static const unsigned RWPS           = (READ|WRITE|SET_VXATTR|SNAPSHOT);
+
+  MDSCapSpec(unsigned _caps=0) : caps(_caps) {
+    if (caps & ALL)
+      caps |= RWPS;
+  }
 
   bool allow_all() const {
-    return any;
+    return (caps & ALL);
+  }
+  bool allow_read() const {
+    return (caps & READ);
+  }
+  bool allow_write() const {
+    return (caps & WRITE);
   }
 
   bool allows(bool r, bool w) const {
-    if (any)
+    if (allow_all())
       return true;
-    if (r && !read)
+    if (r && !allow_read())
       return false;
-    if (w && !write)
+    if (w && !allow_write())
       return false;
     return true;
   }
 
-  bool allows_set_vxattr() const {
-    return set_vxattr;
+  bool allow_snapshot() const {
+    return (caps & SNAPSHOT);
+  }
+  bool allow_set_vxattr() const {
+    return (caps & SET_VXATTR);
   }
+private:
+  unsigned caps;
 };
 
 // conditions before we are allowed to do it
index 9a0aebeef2b26ea5fe69f68c9e5941a930d29c79..770a465199d07b463d009fc1f8e755119a5ea6df 100644 (file)
@@ -9116,7 +9116,7 @@ void Server::handle_client_mksnap(MDRequestRef& mdr)
   if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
     return;
 
-  if (!check_access(mdr, diri, MAY_WRITE))
+  if (!check_access(mdr, diri, MAY_WRITE|MAY_SNAPSHOT))
     return;
 
   // make sure name is unique
@@ -9273,7 +9273,7 @@ void Server::handle_client_rmsnap(MDRequestRef& mdr)
   if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
     return;
 
-  if (!check_access(mdr, diri, MAY_WRITE))
+  if (!check_access(mdr, diri, MAY_WRITE|MAY_SNAPSHOT))
     return;
 
   // prepare
@@ -9420,7 +9420,7 @@ void Server::handle_client_renamesnap(MDRequestRef& mdr)
   if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
     return;
 
-  if (!check_access(mdr, diri, MAY_WRITE))
+  if (!check_access(mdr, diri, MAY_WRITE|MAY_SNAPSHOT))
     return;
 
     // prepare
index 9880681ee233002b06443364fde1680c9dc84947..5cf37eb9caf6c1ba7660ec1e5960ba3442165002 100644 (file)
@@ -1413,13 +1413,33 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op)
         it += 2) {
       const string &path = *it;
       const string &cap = *(it+1);
-      if (cap != "r" && cap != "rw" && cap != "rwp") {
-       ss << "Only 'r', 'rw', and 'rwp' permissions are allowed for filesystems.";
+
+      if (cap != "r" && cap.compare(0, 2, "rw")) {
+       ss << "Permission flags must start with 'r' or 'rw'.";
        err = -EINVAL;
        goto done;
       }
-      if (cap.find('w') != string::npos) {
+      if (cap.compare(0, 2, "rw") == 0)
        osd_cap_wanted = "rw";
+
+      char last='\0';
+      for (size_t i = 2; i < cap.size(); ++i) {
+       char c = cap.at(i);
+       if (last >= c) {
+         ss << "Permission flags (except 'rw') must be specified in alphabetical order.";
+         err = -EINVAL;
+         goto done;
+       }
+       switch (c) {
+       case 'p':
+         break;
+       case 's':
+         break;
+       default:
+         ss << "Unknown permission flag '" << c << "'.";
+         err = -EINVAL;
+         goto done;
+       }
       }
 
       mds_cap_string += mds_cap_string.empty() ? "" : ", ";
index fabb7857895051c97f57fe2bad53c9be31f9e5b6..59e9fb87603cb78d2a8512b095fae03d56d6bb7c 100644 (file)
@@ -235,7 +235,7 @@ TEST(MDSAuthCaps, OutputParsed) {
   };
   CapsTest test_values[] = {
     {"allow",
-     "MDSAuthCaps[allow rw]"},
+     "MDSAuthCaps[allow rwps]"},
     {"allow *",
      "MDSAuthCaps[allow *]"},
     {"allow r",