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
-------------
``foo``, radosgw is able to transparently discern them by their tenant
prefix.
+It is also possible to limit the effects of implicit tenants
+to only apply to swift or s3, by setting ``rgw keystone implicit tenants``
+to either ``s3`` or ``swift``. This will likely primarily
+be of use to users who had previously used implicit tenants
+with older versions of ceph, where implicit tenants
+only applied to the swift protocol.
+
Notes and known issues
----------------------
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?
.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\" />")
<< ", is_admin=" << info.is_admin << ")";
}
+void rgw::auth::ImplicitTenants::recompute_value(const ConfigProxy& 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",
+ nullptr };
+ return keys;
+}
+
+void rgw::auth::ImplicitTenants::handle_conf_change(const ConfigProxy& c,
+ const std::set <std::string> &changed)
+{
+ if (changed.count("rgw_keystone_implicit_tenants")) {
+ recompute_value(c);
+ }
+}
+
void rgw::auth::RemoteApplier::create_account(const DoutPrefixProvider* dpp,
const rgw_user& acct_user,
+ bool implicit_tenant,
RGWUserInfo& user_info) const /* out */
{
rgw_user new_acct_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;
}
* 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
* 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) {
}
}
- if (rgw_get_user_info_by_uid(store, acct_user, user_info) < 0) {
- ldpp_dout(dpp, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl;
- create_account(dpp, 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(dpp, acct_user, implicit_tenant, user_info);
+
/* Succeeded if we are here (create_account() hasn't throwed). */
}
};
};
+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 ConfigProxy& );
+ 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 static_cast<bool>(v&bit);
+ }
+ };
+public:
+ ImplicitTenants(const ConfigProxy& c) { recompute_value(c);}
+ ImplicitTenantValue get_value() {
+ return ImplicitTenantValue(saved);
+ }
+private:
+ const char** get_tracked_conf_keys() const override;
+ void handle_conf_change(const ConfigProxy& 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.
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 DoutPrefixProvider* dpp,
const rgw_user& acct_user,
+ bool implicit_tenant,
RGWUserInfo& user_info) const; /* out */
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 DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override;
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);
}
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),
sts_strategy(cct, store) {
}
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);
}
};
public rgw::auth::RoleApplier::Factory {
typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
RGWRados* const store;
+ rgw::auth::ImplicitTenants& implicit_tenant_context;
STSEngine sts_engine;
) 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));
return aplptr_t(new decltype(apl)(std::move(apl)));
}
public:
STSAuthStrategy(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),
sts_engine(cct, store, *ver_abstractor,
static_cast<rgw::auth::LocalApplier::Factory*>(this),
static_cast<rgw::auth::RemoteApplier::Factory*>(this),
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;
) 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)));
}
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)) {
}
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),
- sts_engine(cct, store, &ver_abstractor),
+ external_engines(cct, store, implicit_tenant_context, &ver_abstractor),
+ sts_engine(cct, store, implicit_tenant_context, &ver_abstractor),
local_engine(cct, store, ver_abstractor,
static_cast<rgw::auth::LocalApplier::Factory*>(this)) {
/* The anonymous auth. */
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)
/* 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);
/* 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);
// 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->svc.zone->get_realm());
#ifdef WITH_RADOSGW_KAFKA_ENDPOINT
rgw::kafka::shutdown();
#endif
+ g_conf().remove_observer(&implicit_tenant_context);
rgw_perf_stop(g_ceph_context);
};
-class S3AuthFactory : public rgw::auth::RemoteApplier::Factory,
- public rgw::auth::LocalApplier::Factory {
- typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
- RGWRados* const store;
-
-public:
- explicit S3AuthFactory(RGWRados* const store)
- : store(store) {
- }
-
- aplptr_t create_apl_remote(CephContext* const cct,
- const req_state* const s,
- rgw::auth::RemoteApplier::acl_strategy_t&& acl_alg,
- const rgw::auth::RemoteApplier::AuthInfo &info
- ) const override {
- return aplptr_t(
- new rgw::auth::RemoteApplier(cct, store, std::move(acl_alg), info,
- cct->_conf->rgw_keystone_implicit_tenants));
- }
-
- aplptr_t create_apl_local(CephContext* const cct,
- const req_state* const s,
- const RGWUserInfo& user_info,
- const std::string& subuser,
- const boost::optional<uint32_t>& perm_mask) const override {
- return aplptr_t(
- new rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask));
- }
-};
-
-
} /* namespace s3 */
} /* namespace auth */
} /* namespace rgw */
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;
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)));
}
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)),