]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: making implicit_tenants backwards compatible. 22363/head
authorMarcus Watts <mwatts@redhat.com>
Wed, 30 May 2018 20:37:31 +0000 (16:37 -0400)
committerMarcus Watts <mwatts@redhat.com>
Tue, 5 Jun 2018 22:32:38 +0000 (18:32 -0400)
In jewel, "rgw keystone implicit tenants" only applied to swift. As of
luminous), this option applies to s3 also.
Sites that used this feature with jewel now have outstanding data that
depends on the old behavior.

The fix here is to expand "rgw keystone implicit tenants" so that it
can be set to any of "none", "all", "s3" or "swift" (also 0=false=none,
1=true=all).  When set to "s3" or "swift", the actual id lookup
is also partitioned.

Formerly "rgw keystone implicit tenants" was a legacy opt.
This change converts it to the new style of option,
including support for dynamically changing it.

Fixes: http://tracker.ceph.com/issues/24348
Signed-off-by: Marcus Watts <mwatts@redhat.com>
(cherry picked from commit a28a38f6e91da3abe59c34fad0e059eeaf29a65f)

12 files changed:
doc/radosgw/keystone.rst
doc/radosgw/multitenancy.rst
src/common/legacy_config_opts.h
src/common/options.cc
src/rgw/rgw_auth.cc
src/rgw/rgw_auth.h
src/rgw/rgw_auth_registry.h
src/rgw/rgw_auth_s3.h
src/rgw/rgw_frontend.h
src/rgw/rgw_main.cc
src/rgw/rgw_rest_s3.h
src/rgw/rgw_swift_auth.h

index 398276c74a57873e9929b6efee9cd603d1e3aa7e..4220b75c53dd992e57e0c8d1368e66fc8c3e9321 100644 (file)
@@ -47,6 +47,13 @@ For a v3 version of the OpenStack Identity API you should replace
    rgw keystone admin domain = {keystone admin domain name}
    rgw keystone admin project = {keystone admin project name}
 
+For compatibility with previous versions of ceph, it is also
+possible to set ``rgw keystone implicit tenants`` to either
+``s3`` or ``swift``.  This has the effect of splitting
+the identity space such that the indicated protocol will
+only use implicit tenants, and the other protocol will
+never use implicit tenants.  Some older versions of ceph
+only supported implicit tenants with swift.
 
 Prior to Kilo
 -------------
index 95f22d7a1d9162e8d4c76b5acdd3dc0f725dc96c..b16f704b399ade5b9ff7bd32afc9e4d428e774b8 100644 (file)
@@ -95,6 +95,7 @@ Swift with Keystone
 TBD -- don't forget to explain the function of
        rgw keystone implicit tenants = true
        in commit e9259486decab52a362443d3fd3dec33b0ec654f
+       [ There is a description of this in keystone.rst ]
 
 Notes and known issues
 ----------------------
index 0651b2070a33c70ad2c11cc73051e787c5381918..e43d0e912492562473443c787931771979389a6a 100644 (file)
@@ -1360,7 +1360,6 @@ OPTION(rgw_keystone_accepted_admin_roles, OPT_STR) // list of roles allowing an
 OPTION(rgw_keystone_token_cache_size, OPT_INT)  // max number of entries in keystone token cache
 OPTION(rgw_keystone_revocation_interval, OPT_INT)  // seconds between tokens revocation check
 OPTION(rgw_keystone_verify_ssl, OPT_BOOL) // should we try to verify keystone's ssl
-OPTION(rgw_keystone_implicit_tenants, OPT_BOOL)  // create new users in their own tenants of the same name
 OPTION(rgw_cross_domain_policy, OPT_STR)
 OPTION(rgw_healthcheck_disabling_path, OPT_STR) // path that existence causes the healthcheck to respond 503
 OPTION(rgw_s3_auth_use_rados, OPT_BOOL)  // should we try to use the internal credentials for s3?
index 5e0596982e7eb302c76cc0152a93dfde69f90417..69a9acdcd89fd3f7504e40dc8095895c9a65712d 100644 (file)
@@ -4624,12 +4624,13 @@ std::vector<Option> get_rgw_options() {
     .set_default(true)
     .set_description("Should RGW verify the Keystone server SSL certificate."),
 
-    Option("rgw_keystone_implicit_tenants", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
-    .set_default(false)
+    Option("rgw_keystone_implicit_tenants", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+    .set_default("false")
+    .set_enum_allowed( { "false", "true", "swift", "s3", "both", "0", "1", "none" } )
     .set_description("RGW Keystone implicit tenants creation")
     .set_long_description(
         "Implicitly create new users in their own tenant with the same name when "
-        "authenticating via Keystone."),
+        "authenticating via Keystone.  Can be limited to s3 or swift only."),
 
     Option("rgw_cross_domain_policy", Option::TYPE_STR, Option::LEVEL_ADVANCED)
     .set_default("<allow-access-from domain=\"*\" secure=\"false\" />")
index 65a8b034f97932b121b68709eebefe90ac067d5e..e18749060fef75e2ad8c8f257338c1b2513096d2 100644 (file)
@@ -385,7 +385,47 @@ void rgw::auth::RemoteApplier::to_str(std::ostream& out) const
       << ", is_admin=" << info.is_admin << ")";
 }
 
+void rgw::auth::ImplicitTenants::recompute_value(const md_config_t *c)
+{
+  std::string s = c->get_val<std::string>("rgw_keystone_implicit_tenants");
+  int v = 0;
+  if (boost::iequals(s, "both")
+    || boost::iequals(s, "true")
+    || boost::iequals(s, "1")) {
+    v = IMPLICIT_TENANTS_S3|IMPLICIT_TENANTS_SWIFT;
+  } else if (boost::iequals(s, "0")
+    || boost::iequals(s, "none")
+    || boost::iequals(s, "false")) {
+    v = 0;
+  } else if (boost::iequals(s, "s3")) {
+    v = IMPLICIT_TENANTS_S3;
+  } else if (boost::iequals(s, "swift")) {
+    v = IMPLICIT_TENANTS_SWIFT;
+  } else {  /* "" (and anything else) */
+    v = IMPLICIT_TENANTS_BAD;
+    // assert(0);
+  }
+  saved = v;
+}
+
+const char **rgw::auth::ImplicitTenants::get_tracked_conf_keys() const
+{
+  static const char *keys[] = {
+    "rgw_keystone_implicit_tenants",
+  NULL };
+  return keys;
+}
+
+void rgw::auth::ImplicitTenants::handle_conf_change(const struct md_config_t *c,
+       const std::set <std::string> &changed)
+{
+  if (changed.count("rgw_keystone_implicit_tenants")) {
+    recompute_value(c);
+  }
+}
+
 void rgw::auth::RemoteApplier::create_account(const rgw_user& acct_user,
+                                              bool implicit_tenant,
                                               RGWUserInfo& user_info) const      /* out */
 {
   rgw_user new_acct_user = acct_user;
@@ -397,7 +437,7 @@ void rgw::auth::RemoteApplier::create_account(const rgw_user& acct_user,
 
   /* An upper layer may enforce creating new accounts within their own
    * tenants. */
-  if (new_acct_user.tenant.empty() && implicit_tenants) {
+  if (new_acct_user.tenant.empty() && implicit_tenant) {
     new_acct_user.tenant = new_acct_user.id;
   }
 
@@ -420,6 +460,9 @@ void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo& user_info) const
    * that belongs to the authenticated identity. Another policy may be
    * applied by using a RGWThirdPartyAccountAuthApplier decorator. */
   const rgw_user& acct_user = info.acct_user;
+  auto implicit_value = implicit_tenant_context.get_value();
+  bool implicit_tenant = implicit_value.implicit_tenants_for_(implicit_tenant_bit);
+  bool split_mode = implicit_value.is_split_mode();
 
   /* Normally, empty "tenant" field of acct_user means the authenticated
    * identity has the legacy, global tenant. However, due to inclusion
@@ -431,8 +474,16 @@ void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo& user_info) const
    * the wiser.
    * If that fails, we look up in the requested (possibly empty) tenant.
    * If that fails too, we create the account within the global or separated
-   * namespace depending on rgw_keystone_implicit_tenants. */
-  if (acct_user.tenant.empty()) {
+   * namespace depending on rgw_keystone_implicit_tenants.
+   * For compatibility with previous versions of ceph, it is possible
+   * to enable implicit_tenants for only s3 or only swift.
+   * in this mode ("split_mode"), we must constrain the id lookups to
+   * only use the identifier space that would be used if the id were
+   * to be created. */
+
+  if (split_mode && !implicit_tenant)
+       ;       /* suppress lookup for id used by "other" protocol */
+  else if (acct_user.tenant.empty()) {
     const rgw_user tenanted_uid(acct_user.id, acct_user.id);
 
     if (rgw_get_user_info_by_uid(store, tenanted_uid, user_info) >= 0) {
@@ -441,11 +492,16 @@ void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo& user_info) const
     }
   }
 
-  if (rgw_get_user_info_by_uid(store, acct_user, user_info) < 0) {
-    ldout(cct, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl;
-    create_account(acct_user, user_info);
+  if (split_mode && implicit_tenant)
+       ;       /* suppress lookup for id used by "other" protocol */
+  else if (rgw_get_user_info_by_uid(store, acct_user, user_info) >= 0) {
+      /* Succeeded. */
+      return;
   }
 
+  ldout(cct, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl;
+  create_account(acct_user, implicit_tenant, user_info);
+
   /* Succeeded if we are here (create_account() hasn't throwed). */
 }
 
index 168498d033316004a6615d3c04ba626405ab5480..bb7e7573abec4b2b6a74bb904aa7ba108e5577aa 100644 (file)
@@ -344,6 +344,43 @@ protected:
  * Each new Strategy should be exposed to it. */
 class StrategyRegistry;
 
+class ImplicitTenants: public md_config_obs_t {
+public:
+  enum implicit_tenant_flag_bits {IMPLICIT_TENANTS_SWIFT=1,
+       IMPLICIT_TENANTS_S3=2, IMPLICIT_TENANTS_BAD = -1, };
+private:
+  int saved;
+  void recompute_value(const md_config_t *);
+  class ImplicitTenantValue {
+    friend class ImplicitTenants;
+    int v;
+    ImplicitTenantValue(int v) : v(v) {};
+  public:
+    bool inline is_split_mode()
+    {
+      assert(v != IMPLICIT_TENANTS_BAD);
+      return v == IMPLICIT_TENANTS_SWIFT || v == IMPLICIT_TENANTS_S3;
+    }
+    bool inline implicit_tenants_for_(const implicit_tenant_flag_bits bit)
+    {
+      assert(v != IMPLICIT_TENANTS_BAD);
+      return !!(v&bit);
+    }
+  };
+public:
+  ImplicitTenants(md_config_t &c) { recompute_value(&c);}
+  ImplicitTenantValue get_value() {
+    return ImplicitTenantValue(saved);
+  }
+private:
+  const char** get_tracked_conf_keys() const override;
+  void handle_conf_change(const struct md_config_t *conf,
+    const std::set <std::string> &changed) override;
+};
+
+std::tuple<bool,bool> implicit_tenants_enabled_for_swift(CephContext * const cct);
+std::tuple<bool,bool> implicit_tenants_enabled_for_s3(CephContext * const cct);
+
 /* rgw::auth::RemoteApplier targets those authentication engines which don't
  * need to ask the RADOS store while performing the auth process. Instead,
  * they obtain credentials from an external source like Keystone or LDAP.
@@ -396,9 +433,11 @@ protected:
   const acl_strategy_t extra_acl_strategy;
 
   const AuthInfo info;
-  const bool implicit_tenants;
+  rgw::auth::ImplicitTenants& implicit_tenant_context;
+  const rgw::auth::ImplicitTenants::implicit_tenant_flag_bits implicit_tenant_bit;
 
   virtual void create_account(const rgw_user& acct_user,
+                              bool implicit_tenant,
                               RGWUserInfo& user_info) const;          /* out */
 
 public:
@@ -406,12 +445,14 @@ public:
                 RGWRados* const store,
                 acl_strategy_t&& extra_acl_strategy,
                 const AuthInfo& info,
-                const bool implicit_tenants)
+               rgw::auth::ImplicitTenants& implicit_tenant_context,
+                rgw::auth::ImplicitTenants::implicit_tenant_flag_bits implicit_tenant_bit)
     : cct(cct),
       store(store),
       extra_acl_strategy(std::move(extra_acl_strategy)),
       info(info),
-      implicit_tenants(implicit_tenants) {
+      implicit_tenant_context(implicit_tenant_context),
+      implicit_tenant_bit(implicit_tenant_bit) {
   }
 
   uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override;
index 08a93c73dac2f4c9bb52ad87a2b6135c209ab85d..494fbfe5e4fde23a813f205e00ac9cf293f7c92d 100644 (file)
@@ -35,9 +35,11 @@ class StrategyRegistry {
     s3_main_strategy_plain_t s3_main_strategy_plain;
     s3_main_strategy_boto2_t s3_main_strategy_boto2;
 
-    s3_main_strategy_t(CephContext* const cct, RGWRados* const store)
-      : s3_main_strategy_plain(cct, store),
-        s3_main_strategy_boto2(cct, store) {
+    s3_main_strategy_t(CephContext* const cct,
+                      ImplicitTenants& implicit_tenant_context,
+                      RGWRados* const store)
+      : s3_main_strategy_plain(cct, implicit_tenant_context, store),
+        s3_main_strategy_boto2(cct, implicit_tenant_context, store) {
       add_engine(Strategy::Control::SUFFICIENT, s3_main_strategy_plain);
       add_engine(Strategy::Control::FALLBACK, s3_main_strategy_boto2);
     }
@@ -55,10 +57,11 @@ class StrategyRegistry {
 
 public:
   StrategyRegistry(CephContext* const cct,
+                   ImplicitTenants& implicit_tenant_context,
                    RGWRados* const store)
-    : s3_main_strategy(cct, store),
-      s3_post_strategy(cct, store),
-      swift_strategy(cct, store) {
+    : s3_main_strategy(cct, implicit_tenant_context, store),
+      s3_post_strategy(cct, implicit_tenant_context, store),
+      swift_strategy(cct, implicit_tenant_context, store) {
   }
 
   const s3_main_strategy_t& get_s3_main() const {
@@ -75,8 +78,9 @@ public:
 
   static std::shared_ptr<StrategyRegistry>
   create(CephContext* const cct,
+         ImplicitTenants& implicit_tenant_context,
          RGWRados* const store) {
-    return std::make_shared<StrategyRegistry>(cct, store);
+    return std::make_shared<StrategyRegistry>(cct, implicit_tenant_context, store);
   }
 };
 
index ca84672d89dd2620d8d73696238247299075acf7..2a875d4798f021d2251d9087c2502b1379d70b94 100644 (file)
@@ -36,6 +36,7 @@ class ExternalAuthStrategy : public rgw::auth::Strategy,
                              public rgw::auth::RemoteApplier::Factory {
   typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
   RGWRados* const store;
+  rgw::auth::ImplicitTenants& implicit_tenant_context;
 
   using keystone_config_t = rgw::keystone::CephCtxConfig;
   using keystone_cache_t = rgw::keystone::TokenCache;
@@ -51,7 +52,8 @@ class ExternalAuthStrategy : public rgw::auth::Strategy,
                             ) const override {
     auto apl = rgw::auth::add_sysreq(cct, store, s,
       rgw::auth::RemoteApplier(cct, store, std::move(acl_alg), info,
-                               cct->_conf->rgw_keystone_implicit_tenants));
+                               implicit_tenant_context,
+                               rgw::auth::ImplicitTenants::IMPLICIT_TENANTS_S3));
     /* TODO(rzarzynski): replace with static_ptr. */
     return aplptr_t(new decltype(apl)(std::move(apl)));
   }
@@ -59,8 +61,10 @@ class ExternalAuthStrategy : public rgw::auth::Strategy,
 public:
   ExternalAuthStrategy(CephContext* const cct,
                        RGWRados* const store,
+                       rgw::auth::ImplicitTenants& implicit_tenant_context,
                        AWSEngine::VersionAbstractor* const ver_abstractor)
     : store(store),
+      implicit_tenant_context(implicit_tenant_context),
       ldap_engine(cct, store, *ver_abstractor,
                   static_cast<rgw::auth::RemoteApplier::Factory*>(this)) {
 
@@ -116,12 +120,13 @@ class AWSAuthStrategy : public rgw::auth::Strategy,
 
 public:
   AWSAuthStrategy(CephContext* const cct,
+                  rgw::auth::ImplicitTenants& implicit_tenant_context,
                   RGWRados* const store)
     : store(store),
       ver_abstractor(cct),
       anonymous_engine(cct,
                        static_cast<rgw::auth::LocalApplier::Factory*>(this)),
-      external_engines(cct, store, &ver_abstractor),
+      external_engines(cct, store, implicit_tenant_context, &ver_abstractor),
       local_engine(cct, store, ver_abstractor,
                    static_cast<rgw::auth::LocalApplier::Factory*>(this)) {
     /* The anynoymous auth. */
index c5d9613536d28c212c1cc28f783748e28d9c9f26..2ee4a9b31c23db47025e86a35318717871554375 100644 (file)
@@ -246,11 +246,16 @@ public:
 class RGWFrontendPauser : public RGWRealmReloader::Pauser {
   std::list<RGWFrontend*> &frontends;
   RGWRealmReloader::Pauser* pauser;
+  rgw::auth::ImplicitTenants& implicit_tenants;
 
  public:
   RGWFrontendPauser(std::list<RGWFrontend*> &frontends,
+                    rgw::auth::ImplicitTenants& implicit_tenants,
                     RGWRealmReloader::Pauser* pauser = nullptr)
-    : frontends(frontends), pauser(pauser) {}
+    : frontends(frontends),
+      pauser(pauser),
+      implicit_tenants(implicit_tenants) {
+  }
 
   void pause() override {
     for (auto frontend : frontends)
@@ -262,7 +267,7 @@ class RGWFrontendPauser : public RGWRealmReloader::Pauser {
     /* Initialize the registry of auth strategies which will coordinate
      * the dynamic reconfiguration. */
     auto auth_registry = \
-      rgw::auth::StrategyRegistry::create(g_ceph_context, store);
+      rgw::auth::StrategyRegistry::create(g_ceph_context, implicit_tenants, store);
 
     for (auto frontend : frontends)
       frontend->unpause_with_new_config(store, auth_registry);
index 8c0814a4480c826aa8c87eaf9fbfbe6c4637aa08..5fade44310b22628de0c01d7f72f8d1c75b340dd 100644 (file)
@@ -422,8 +422,10 @@ int main(int argc, const char **argv)
 
   /* Initialize the registry of auth strategies which will coordinate
    * the dynamic reconfiguration. */
+  rgw::auth::ImplicitTenants implicit_tenant_context{*g_conf};
+  g_conf->add_observer(&implicit_tenant_context);
   auto auth_registry = \
-    rgw::auth::StrategyRegistry::create(g_ceph_context, store);
+    rgw::auth::StrategyRegistry::create(g_ceph_context, implicit_tenant_context, store);
 
   /* Header custom behavior */
   rest.register_x_headers(g_conf->rgw_log_http_headers);
@@ -535,7 +537,7 @@ int main(int argc, const char **argv)
 
   // add a watcher to respond to realm configuration changes
   RGWPeriodPusher pusher(store);
-  RGWFrontendPauser pauser(fes, &pusher);
+  RGWFrontendPauser pauser(fes, implicit_tenant_context, &pusher);
   RGWRealmReloader reloader(store, service_map_meta, &pauser);
 
   RGWRealmWatcher realm_watcher(g_ceph_context, store->realm);
@@ -586,6 +588,7 @@ int main(int argc, const char **argv)
   rgw_tools_cleanup();
   rgw_shutdown_resolver();
   rgw::curl::cleanup_curl();
+  g_conf->remove_observer(&implicit_tenant_context);
 
   rgw_perf_stop(g_ceph_context);
 
index e8afaa3fa92a87302b8104a3a37c1a50eb6f9ad5..506f5f4c57b4eee90d75bb9f8692890717484aea 100644 (file)
@@ -891,14 +891,18 @@ public:
 };
 
 
+#if 0
 class S3AuthFactory : public rgw::auth::RemoteApplier::Factory,
                       public rgw::auth::LocalApplier::Factory {
   typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
   RGWRados* const store;
+  ImplicitTenants& implicit_tenant_context;
 
 public:
-  S3AuthFactory(RGWRados* const store)
-    : store(store) {
+  S3AuthFactory(RGWRados* const store,
+               ImplicitTenants& implicit_tenant_context)
+    : store(store),
+      implicit_tenant_context(implicit_tenant_context) {
   }
 
   aplptr_t create_apl_remote(CephContext* const cct,
@@ -908,7 +912,8 @@ public:
                             ) const override {
     return aplptr_t(
       new rgw::auth::RemoteApplier(cct, store, std::move(acl_alg), info,
-                                   cct->_conf->rgw_keystone_implicit_tenants));
+                                   implicit_tenant_context,
+                                   rgw::auth::ImplicitTenants::IMPLICIT_TENANTS_S3));
   }
 
   aplptr_t create_apl_local(CephContext* const cct,
@@ -919,6 +924,7 @@ public:
         new rgw::auth::LocalApplier(cct, user_info, subuser));
   }
 };
+#endif
 
 
 } /* namespace s3 */
index cc508202db855fd5e07be02eec58d6df0026d48f..f778e361166a0998d7d76b11c94d130c20a82dcb 100644 (file)
@@ -164,6 +164,7 @@ class DefaultStrategy : public rgw::auth::Strategy,
                         public rgw::auth::LocalApplier::Factory,
                         public rgw::auth::swift::TempURLApplier::Factory {
   RGWRados* const store;
+  ImplicitTenants& implicit_tenant_context;
 
   /* The engines. */
   const rgw::auth::swift::TempURLEngine tempurl_engine;
@@ -192,7 +193,8 @@ class DefaultStrategy : public rgw::auth::Strategy,
       rgw::auth::add_3rdparty(store, s->account_name,
         rgw::auth::add_sysreq(cct, store, s,
           rgw::auth::RemoteApplier(cct, store, std::move(extra_acl_strategy), info,
-                                   cct->_conf->rgw_keystone_implicit_tenants)));
+                                   implicit_tenant_context,
+                                   rgw::auth::ImplicitTenants::IMPLICIT_TENANTS_SWIFT)));
     /* TODO(rzarzynski): replace with static_ptr. */
     return aplptr_t(new decltype(apl)(std::move(apl)));
   }
@@ -220,8 +222,10 @@ class DefaultStrategy : public rgw::auth::Strategy,
 
 public:
   DefaultStrategy(CephContext* const cct,
+                  ImplicitTenants& implicit_tenant_context,
                   RGWRados* const store)
     : store(store),
+      implicit_tenant_context(implicit_tenant_context),
       tempurl_engine(cct,
                      store,
                      static_cast<rgw::auth::swift::TempURLApplier::Factory*>(this)),