From: Pritha Srivastava Date: Tue, 31 Mar 2020 10:07:20 +0000 (+0530) Subject: rgw: adds code for role session to be used an ARN. X-Git-Tag: v15.2.9~122^2~4^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6c6b54e6f014da8c5020a544b0c52bd1f8cd00db;p=ceph.git rgw: adds code for role session to be used an ARN. Signed-off-by: Pritha Srivastava (cherry picked from commit 039a2b9ce52e3ed2c5422423deaf27c32de3773e) --- diff --git a/src/rgw/rgw_auth.cc b/src/rgw/rgw_auth.cc index 705d3e81cea5..22d8ccd0d49e 100644 --- a/src/rgw/rgw_auth.cc +++ b/src/rgw/rgw_auth.cc @@ -2,6 +2,7 @@ // vim: ts=8 sw=2 smarttab ft=cpp #include +#include #include "rgw_common.h" #include "rgw_auth.h" @@ -363,11 +364,12 @@ void rgw::auth::WebIdentityApplier::modify_request_state(const DoutPrefixProvide string idp_url = get_idp_url(); string condition = idp_url + ":app_id"; - if (! token_claims.client_id.empty()) { - s->env.emplace(condition, token_claims.client_id); - } else { - s->env.emplace(condition, token_claims.aud); - } + + s->env.emplace(condition, token_claims.aud); + + condition.clear(); + condition = idp_url + ":sub"; + s->env.emplace(condition, token_claims.sub); } bool rgw::auth::WebIdentityApplier::is_identity(const idset_t& ids) const @@ -670,26 +672,35 @@ void rgw::auth::LocalApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWU } void rgw::auth::RoleApplier::to_str(std::ostream& out) const { - out << "rgw::auth::LocalApplier(role name =" << role_name; - for (auto policy : role_policies) { + out << "rgw::auth::LocalApplier(role name =" << role.name; + for (auto& policy: role.role_policies) { out << ", role policy =" << policy; } + out << ", token policy =" << token_policy; out << ")"; } bool rgw::auth::RoleApplier::is_identity(const idset_t& ids) const { for (auto& p : ids) { - string name; - string tenant = p.get_tenant(); - if (tenant.empty()) { - name = p.get_id(); - } else { - name = tenant + "$" + p.get_id(); - } if (p.is_wildcard()) { return true; - } else if (p.is_role() && name == role_name) { - return true; + } else if (p.is_role()) { + string name = p.get_id(); + string tenant = p.get_tenant(); + if (name == role.name && tenant == role.tenant) { + return true; + } + } else if (p.is_assumed_role()) { + string tenant = p.get_tenant(); + string role_session = role.name + "/" + role_session_name; //role/role-session + if (role.tenant == tenant && role_session == p.get_role_session()) { + return true; + } + } else { + string id = p.get_id(); + if (user_id.id == id) { + return true; + } } } return false; @@ -699,21 +710,38 @@ void rgw::auth::RoleApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWUs { /* Load the user id */ user_info.user_id = this->user_id; + + user_info.user_id.tenant = role.tenant; } void rgw::auth::RoleApplier::modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const { - for (auto it : role_policies) { + for (auto it: role.role_policies) { try { bufferlist bl = bufferlist::static_from_string(it); - const rgw::IAM::Policy p(s->cct, s->user->get_tenant(), bl); + const rgw::IAM::Policy p(s->cct, role.tenant, bl); s->iam_user_policies.push_back(std::move(p)); } catch (rgw::IAM::PolicyParseException& e) { //Control shouldn't reach here as the policy has already been //verified earlier - ldpp_dout(dpp, 20) << "failed to parse policy: " << e.what() << dendl; + ldpp_dout(dpp, 20) << "failed to parse role policy: " << e.what() << dendl; } } + + try { + string policy = this->token_policy; + bufferlist bl = bufferlist::static_from_string(policy); + const rgw::IAM::Policy p(s->cct, role.tenant, bl); + s->iam_user_policies.push_back(std::move(p)); + } catch (rgw::IAM::PolicyParseException& e) { + //Control shouldn't reach here as the policy has already been + //verified earlier + ldpp_dout(dpp, 20) << "failed to parse token policy: " << e.what() << dendl; + } + + string condition = "aws:userid"; + string value = role.id + ":" + role_session_name; + s->env.emplace(condition, value); } rgw::auth::Engine::result_t diff --git a/src/rgw/rgw_auth.h b/src/rgw/rgw_auth.h index fda81e8423a9..e9a243dbb716 100644 --- a/src/rgw/rgw_auth.h +++ b/src/rgw/rgw_auth.h @@ -365,6 +365,7 @@ class WebIdentityApplier : public IdentityApplier { protected: CephContext* const cct; RGWCtl* const ctl; + string role_session; rgw::web_idp::WebTokenClaims token_claims; string get_idp_url() const; @@ -372,9 +373,11 @@ protected: public: WebIdentityApplier( CephContext* const cct, RGWCtl* const ctl, + const string& role_session, const rgw::web_idp::WebTokenClaims& token_claims) : cct(cct), ctl(ctl), + role_session(role_session), token_claims(token_claims) { } @@ -422,6 +425,7 @@ public: virtual aplptr_t create_apl_web_identity( CephContext* cct, const req_state* s, + const string& role_session, const rgw::web_idp::WebTokenClaims& token) const = 0; }; }; @@ -623,20 +627,29 @@ public: }; class RoleApplier : public IdentityApplier { +public: + struct Role { + string id; + string name; + string tenant; + vector role_policies; + } role; protected: - const string role_name; const rgw_user user_id; - vector role_policies; + string token_policy; + string role_session_name; public: RoleApplier(CephContext* const cct, - const string& role_name, + const Role& role, const rgw_user& user_id, - const vector& role_policies) - : role_name(role_name), + const string& token_policy, + const string& role_session_name) + : role(role), user_id(user_id), - role_policies(role_policies) {} + token_policy(token_policy), + role_session_name(role_session_name) {} uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override { return 0; @@ -662,9 +675,10 @@ public: virtual ~Factory() {} virtual aplptr_t create_apl_role( CephContext* cct, const req_state* s, - const string& role_name, + const rgw::auth::RoleApplier::Role& role_name, const rgw_user& user_id, - const vector& role_policies) const = 0; + const std::string& token_policy, + const std::string& role_session) const = 0; }; }; diff --git a/src/rgw/rgw_auth_s3.h b/src/rgw/rgw_auth_s3.h index 9e79ee162136..0809ee854eb8 100644 --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@ -65,11 +65,12 @@ class STSAuthStrategy : public rgw::auth::Strategy, aplptr_t create_apl_role(CephContext* const cct, const req_state* const s, - const string& role_name, + const rgw::auth::RoleApplier::Role& role, const rgw_user& user_id, - const vector& role_policies) const override { + const std::string& token_policy, + const std::string& role_session_name) const override { auto apl = rgw::auth::add_sysreq(cct, ctl, s, - rgw::auth::RoleApplier(cct, role_name, user_id, role_policies)); + rgw::auth::RoleApplier(cct, role, user_id, token_policy, role_session_name)); return aplptr_t(new decltype(apl)(std::move(apl))); } diff --git a/src/rgw/rgw_basic_types.h b/src/rgw/rgw_basic_types.h index 0ba03bd0e27f..f7f742a011ab 100644 --- a/src/rgw/rgw_basic_types.h +++ b/src/rgw/rgw_basic_types.h @@ -486,7 +486,7 @@ void decode_json_obj(rgw_zone_id& zid, JSONObj *obj); namespace rgw { namespace auth { class Principal { - enum types { User, Role, Tenant, Wildcard, OidcProvider }; + enum types { User, Role, Tenant, Wildcard, OidcProvider, AssumedRole }; types t; rgw_user u; string idp_url; @@ -522,6 +522,10 @@ public: return Principal(std::move(idp_url)); } + static Principal assumed_role(std::string&& t, std::string&& u) { + return Principal(AssumedRole, std::move(t), std::move(u)); + } + bool is_wildcard() const { return t == Wildcard; } @@ -542,6 +546,10 @@ public: return t == OidcProvider; } + bool is_assumed_role() const { + return t == AssumedRole; + } + const std::string& get_tenant() const { return u.tenant; } @@ -554,6 +562,14 @@ public: return idp_url; } + const string& get_role_session() const { + return u.id; + } + + const string& get_role() const { + return u.id; + } + bool operator ==(const Principal& o) const { return (t == o.t) && (u == o.u); } diff --git a/src/rgw/rgw_iam_policy.cc b/src/rgw/rgw_iam_policy.cc index 900eb11d4f19..f43b20ee5f3c 100644 --- a/src/rgw/rgw_iam_policy.cc +++ b/src/rgw/rgw_iam_policy.cc @@ -466,6 +466,9 @@ static boost::optional parse_principal(CephContext* cct, TokenID t, if (match[1] == "oidc-provider") { return Principal::oidc_provider(std::move(match[2])); } + if (match[1] == "assumed-role") { + return Principal::assumed_role(std::move(a->account), match[2]); + } } } else { if (std::none_of(s.begin(), s.end(), diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 3a4f7e0c523c..d8738a4f5b47 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -5906,26 +5906,26 @@ rgw::auth::s3::STSEngine::authenticate( // Get all the authorization info RGWUserInfo user_info; rgw_user user_id; - vector role_policies; - string role_name; + string role_id; + rgw::auth::RoleApplier::Role r; if (! token.roleId.empty()) { RGWRole role(s->cct, ctl, token.roleId); if (role.get_by_id() < 0) { return result_t::deny(-EPERM); } + r.id = token.roleId; + r.name = role.get_name(); + r.tenant = role.get_tenant(); + vector role_policy_names = role.get_role_policy_names(); for (auto& policy_name : role_policy_names) { string perm_policy; if (int ret = role.get_role_policy(policy_name, perm_policy); ret == 0) { - role_policies.push_back(std::move(perm_policy)); + r.role_policies.push_back(std::move(perm_policy)); } } - if (! token.policy.empty()) { - role_policies.push_back(std::move(token.policy)); - } // This is mostly needed to assign the owner of a bucket during its creation user_id = token.user; - role_name = role.get_name(); } if (! token.user.empty() && token.acct_type != TYPE_ROLE) { @@ -5942,7 +5942,7 @@ rgw::auth::s3::STSEngine::authenticate( get_creds_info(token)); return result_t::grant(std::move(apl), completer_factory(boost::none)); } else if (token.acct_type == TYPE_ROLE) { - auto apl = role_apl_factory->create_apl_role(cct, s, role_name, user_id, role_policies); + auto apl = role_apl_factory->create_apl_role(cct, s, r, user_id, token.policy, token.role_session); return result_t::grant(std::move(apl), completer_factory(token.secret_access_key)); } else { // This is for all local users of type TYPE_RGW or TYPE_NONE string subuser; diff --git a/src/rgw/rgw_rest_sts.cc b/src/rgw/rgw_rest_sts.cc index e229b0a95054..729c61e2e515 100644 --- a/src/rgw/rgw_rest_sts.cc +++ b/src/rgw/rgw_rest_sts.cc @@ -328,7 +328,11 @@ WebTokenEngine::authenticate( const DoutPrefixProvider* dpp, } if (t) { - auto apl = apl_factory->create_apl_web_identity(cct, s, *t); + string role_session = s->info.args.get("RoleSessionName"); + if (role_session.empty()) { + return result_t::deny(-EACCES); + } + auto apl = apl_factory->create_apl_web_identity(cct, s, role_session, *t); return result_t::grant(std::move(apl)); } return result_t::deny(-EACCES); diff --git a/src/rgw/rgw_rest_sts.h b/src/rgw/rgw_rest_sts.h index 79333f5043ae..d7227fe5af6c 100644 --- a/src/rgw/rgw_rest_sts.h +++ b/src/rgw/rgw_rest_sts.h @@ -77,9 +77,10 @@ class DefaultStrategy : public rgw::auth::Strategy, aplptr_t create_apl_web_identity( CephContext* cct, const req_state* s, + const string& role_session, const rgw::web_idp::WebTokenClaims& token) const override { auto apl = rgw::auth::add_sysreq(cct, ctl, s, - rgw::auth::WebIdentityApplier(cct, ctl, token)); + rgw::auth::WebIdentityApplier(cct, ctl, role_session, token)); return aplptr_t(new decltype(apl)(std::move(apl))); } diff --git a/src/rgw/rgw_role.h b/src/rgw/rgw_role.h index 8df22f6844fb..fceb4fb63547 100644 --- a/src/rgw/rgw_role.h +++ b/src/rgw/rgw_role.h @@ -40,7 +40,6 @@ class RGWRole int read_id(const string& role_name, const string& tenant, string& role_id); int read_name(); int read_info(); - void set_id(const string& id) { this->id = id; } bool validate_input(); void extract_name_tenant(const std::string& str); @@ -129,11 +128,14 @@ public: const string& get_id() const { return id; } const string& get_name() const { return name; } + const string& get_tenant() const { return tenant; } const string& get_path() const { return path; } const string& get_create_date() const { return creation_date; } const string& get_assume_role_policy() const { return trust_policy;} const uint64_t& get_max_session_duration() const { return max_session_duration; } + void set_id(const string& id) { this->id = id; } + int create(bool exclusive); int delete_obj(); int get(); diff --git a/src/rgw/rgw_sts.cc b/src/rgw/rgw_sts.cc index de4e33fb4aa7..ca813c244b61 100644 --- a/src/rgw/rgw_sts.cc +++ b/src/rgw/rgw_sts.cc @@ -44,6 +44,7 @@ int Credentials::generateCredentials(CephContext* cct, const uint64_t& duration, const boost::optional& policy, const boost::optional& roleId, + const boost::optional& role_session, boost::optional user, rgw::auth::Identity* identity) { @@ -117,6 +118,7 @@ int Credentials::generateCredentials(CephContext* cct, token.perm_mask = 0; token.is_admin = 0; token.acct_type = TYPE_ROLE; + token.role_session = role_session.get(); } buffer::list input, enc_output; @@ -335,6 +337,7 @@ AssumeRoleWithWebIdentityResponse STSService::assumeRoleWithWebIdentity(AssumeRo //Role and Policy provide the authorization info, user id and applier info are not needed response.assumeRoleResp.retCode = response.assumeRoleResp.creds.generateCredentials(cct, req.getDuration(), req.getPolicy(), roleId, + req.getRoleSessionName(), user_id, nullptr); if (response.assumeRoleResp.retCode < 0) { return response; @@ -380,6 +383,7 @@ AssumeRoleResponse STSService::assumeRole(AssumeRoleRequest& req) //Role and Policy provide the authorization info, user id and applier info are not needed response.retCode = response.creds.generateCredentials(cct, req.getDuration(), req.getPolicy(), roleId, + req.getRoleSessionName(), user_id, nullptr); if (response.retCode < 0) { return response; @@ -417,6 +421,7 @@ GetSessionTokenResponse STSService::getSessionToken(GetSessionTokenRequest& req) req.getDuration(), boost::none, boost::none, + boost::none, user_id, identity); ret < 0) { return make_tuple(ret, cred); diff --git a/src/rgw/rgw_sts.h b/src/rgw/rgw_sts.h index 86b621a30852..fa8cc70295da 100644 --- a/src/rgw/rgw_sts.h +++ b/src/rgw/rgw_sts.h @@ -128,11 +128,12 @@ struct SessionToken { uint32_t perm_mask; bool is_admin; uint32_t acct_type; + string role_session; SessionToken() {} void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); + ENCODE_START(2, 1, bl); encode(access_key_id, bl); encode(secret_access_key, bl); encode(expiration, bl); @@ -143,11 +144,12 @@ struct SessionToken { encode(perm_mask, bl); encode(is_admin, bl); encode(acct_type, bl); + encode(role_session, bl); ENCODE_FINISH(bl); } void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); + DECODE_START(2, bl); decode(access_key_id, bl); decode(secret_access_key, bl); decode(expiration, bl); @@ -158,6 +160,9 @@ struct SessionToken { decode(perm_mask, bl); decode(is_admin, bl); decode(acct_type, bl); + if (struct_v >= 2) { + decode(role_session, bl); + } DECODE_FINISH(bl); } }; @@ -175,6 +180,7 @@ public: const uint64_t& duration, const boost::optional& policy, const boost::optional& roleId, + const boost::optional& role_session, boost::optional user, rgw::auth::Identity* identity); const string& getAccessKeyId() const { return accessKeyId; }