From: Pritha Srivastava Date: Fri, 7 May 2021 13:06:23 +0000 (+0530) Subject: rgw/sts: code to add s3:ResourceTag to IAM environment X-Git-Tag: v16.2.11~244^2~9 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=68fa2848e995c17b29cb9cd2e9f3a0c882eef903;p=ceph.git rgw/sts: code to add s3:ResourceTag to IAM environment for objects and buckets, that will be used in evaluation of Condition element in the IAM policies. Signed-off-by: Pritha Srivastava (cherry picked from commit fd0da48c3ff80fb920b4bb6f3ee91bc274afc3b7) --- diff --git a/src/rgw/rgw_iam_policy.h b/src/rgw/rgw_iam_policy.h index 0813778f9c5..179f0ffb3cb 100644 --- a/src/rgw/rgw_iam_policy.h +++ b/src/rgw/rgw_iam_policy.h @@ -443,6 +443,15 @@ struct Condition { bool has_key_p(const std::string& _key, F p) const { return p(key, _key); } + + template + bool has_val_p(const std::string& _val, F p) const { + for (auto val : vals) { + if (p(val, _val)) + return true; + } + return false; + } }; std::ostream& operator <<(std::ostream& m, const Condition& c); @@ -516,13 +525,28 @@ struct Policy { return false; } - bool has_conditional(const string& c) const { + template + bool has_conditional_value(const std::string& conditional, F p) const { + for (const auto&s: statements){ + if (std::any_of(s.conditions.begin(), s.conditions.end(), + [&](const Condition& c) { return c.has_val_p(conditional, p);})) + return true; + } + return false; + } + + bool has_conditional(const std::string& c) const { return has_conditional(c, Condition::ci_equal_to()); } bool has_partial_conditional(const string& c) const { return has_conditional(c, Condition::ci_starts_with()); } + + // Example: ${s3:ResourceTag} + bool has_partial_conditional_value(const std::string& c) const { + return has_conditional_value(c, Condition::ci_starts_with()); + } }; std::ostream& operator <<(ostream& m, const Policy& p); diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 7f9cdf71d98..89ff4931d9e 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -95,6 +95,8 @@ static MultipartMetaFilter mp_filter; // this probably should belong in the rgw_iam_policy_keywords, I'll get it to it // at some point static constexpr auto S3_EXISTING_OBJTAG = "s3:ExistingObjectTag"; +static constexpr auto S3_RESOURCE_TAG = "s3:ResourceTag"; +static constexpr auto S3_RUNTIME_RESOURCE_VAL = "${s3:ResourceTag"; int RGWGetObj::parse_range(void) { @@ -755,6 +757,56 @@ int rgw_build_object_policies(const DoutPrefixProvider *dpp, rgw::sal::RGWRadosS return ret; } +static int rgw_iam_remove_objtags(const DoutPrefixProvider *dpp, struct req_state* s, rgw::sal::RGWObject* object, bool has_existing_obj_tag, bool has_resource_tag) { + object->set_atomic(s->obj_ctx); + int op_ret = object->get_obj_attrs(s->obj_ctx, s->yield, dpp); + if (op_ret < 0) + return op_ret; + rgw::sal::RGWAttrs attrs = object->get_attrs(); + auto tags = attrs.find(RGW_ATTR_TAGS); + if (tags != attrs.end()) { + RGWObjTags tagset; + try { + auto bliter = tags->second.cbegin(); + tagset.decode(bliter); + } catch (buffer::error& err) { + ldpp_dout(s, 0) << "ERROR: caught buffer::error, couldn't decode TagSet" << dendl; + return -EIO; + } + for (auto& tag: tagset.get_tags()) { + if (has_existing_obj_tag) { + vector::iterator> iters; + string key = "s3:ExistingObjectTag/" + tag.first; + auto result = s->env.equal_range(key); + for (auto& it = result.first; it != result.second; ++it) + { + if (tag.second == it->second) { + iters.emplace_back(it); + } + } + for (auto& it : iters) { + s->env.erase(it); + } + }//end if has_existing_obj_tag + if (has_resource_tag) { + vector::iterator> iters; + string key = "s3:ResourceTag/" + tag.first; + auto result = s->env.equal_range(key); + for (auto& it = result.first; it != result.second; ++it) + { + if (tag.second == it->second) { + iters.emplace_back(it); + } + } + for (auto& it : iters) { + s->env.erase(it); + } + }//end if has_resource_tag + } + } + return 0; +} + void rgw_add_to_iam_environment(rgw::IAM::Environment& e, std::string_view key, std::string_view val){ // This variant just adds non empty key pairs to IAM env., values can be empty // in certain cases like tagging @@ -762,7 +814,7 @@ void rgw_add_to_iam_environment(rgw::IAM::Environment& e, std::string_view key, e.emplace(key,val); } -static int rgw_iam_add_tags_from_bl(struct req_state* s, bufferlist& bl){ +static int rgw_iam_add_tags_from_bl(struct req_state* s, bufferlist& bl, bool has_existing_obj_tag=false, bool has_resource_tag=false){ RGWObjTags& tagset = s->tagset; try { auto bliter = bl.cbegin(); @@ -773,24 +825,98 @@ static int rgw_iam_add_tags_from_bl(struct req_state* s, bufferlist& bl){ } for (const auto& tag: tagset.get_tags()){ - rgw_add_to_iam_environment(s->env, "s3:ExistingObjectTag/" + tag.first, tag.second); + if (has_existing_obj_tag) + rgw_add_to_iam_environment(s->env, "s3:ExistingObjectTag/" + tag.first, tag.second); + if (has_resource_tag) + rgw_add_to_iam_environment(s->env, "s3:ResourceTag/" + tag.first, tag.second); } return 0; } -static int rgw_iam_add_existing_objtags(const DoutPrefixProvider *dpp, rgw::sal::RGWRadosStore* store, struct req_state* s, std::uint64_t action) { - s->object->set_atomic(s->obj_ctx); - int op_ret = s->object->get_obj_attrs(s->obj_ctx, s->yield, dpp); +static int rgw_iam_add_objtags(const DoutPrefixProvider *dpp, struct req_state* s, rgw::sal::RGWObject* object, bool has_existing_obj_tag, bool has_resource_tag) { + object->set_atomic(s->obj_ctx); + int op_ret = object->get_obj_attrs(s->obj_ctx, s->yield, dpp); if (op_ret < 0) return op_ret; - rgw::sal::RGWAttrs attrs = s->object->get_attrs(); + rgw::sal::RGWAttrs attrs = object->get_attrs(); auto tags = attrs.find(RGW_ATTR_TAGS); if (tags != attrs.end()){ - return rgw_iam_add_tags_from_bl(s, tags->second); + return rgw_iam_add_tags_from_bl(s, tags->second, has_existing_obj_tag, has_resource_tag); } return 0; } +static int rgw_iam_add_objtags(const DoutPrefixProvider *dpp, struct req_state* s, bool has_existing_obj_tag, bool has_resource_tag) { + if (!rgw::sal::RGWObject::empty(s->object.get())) { + return rgw_iam_add_objtags(dpp, s, s->object.get(), has_existing_obj_tag, has_resource_tag); + } + return 0; +} + +static int rgw_iam_add_buckettags(const DoutPrefixProvider *dpp, struct req_state* s, rgw::sal::RGWBucket* bucket) { + rgw::sal::RGWAttrs attrs = bucket->get_attrs(); + auto tags = attrs.find(RGW_ATTR_TAGS); + if (tags != attrs.end()) { + return rgw_iam_add_tags_from_bl(s, tags->second, false, true); + } + return 0; +} + +static int rgw_iam_add_buckettags(const DoutPrefixProvider *dpp, struct req_state* s) { + return rgw_iam_add_buckettags(dpp, s, s->bucket.get()); +} + +static std::tuple rgw_check_policy_condition(const DoutPrefixProvider *dpp, + boost::optional iam_policy, + boost::optional> identity_policies, + boost::optional> session_policies, + bool check_obj_exist_tag=true) { + bool has_existing_obj_tag = false, has_resource_tag = false; + bool iam_policy_s3_exist_tag = false, iam_policy_s3_resource_tag = false; + if (iam_policy) { + if (check_obj_exist_tag) { + iam_policy_s3_exist_tag = iam_policy->has_partial_conditional(S3_EXISTING_OBJTAG); + } + iam_policy_s3_resource_tag = iam_policy->has_partial_conditional(S3_RESOURCE_TAG) || iam_policy->has_partial_conditional_value(S3_RUNTIME_RESOURCE_VAL); + } + + bool identity_policy_s3_exist_tag = false, identity_policy_s3_resource_tag = false; + if (identity_policies) { + for (auto& identity_policy : identity_policies.get()) { + if (check_obj_exist_tag) { + if (identity_policy.has_partial_conditional(S3_EXISTING_OBJTAG)) + identity_policy_s3_exist_tag = true; + } + if (identity_policy.has_partial_conditional(S3_RESOURCE_TAG) || identity_policy.has_partial_conditional_value(S3_RUNTIME_RESOURCE_VAL)) + identity_policy_s3_resource_tag = true; + if (identity_policy_s3_exist_tag && identity_policy_s3_resource_tag) // check all policies till both are set to true + break; + } + } + + bool session_policy_s3_exist_tag = false, session_policy_s3_resource_flag = false; + if (session_policies) { + for (auto& session_policy : session_policies.get()) { + if (check_obj_exist_tag) { + if (session_policy.has_partial_conditional(S3_EXISTING_OBJTAG)) + session_policy_s3_exist_tag = true; + } + if (session_policy.has_partial_conditional(S3_RESOURCE_TAG) || session_policy.has_partial_conditional_value(S3_RUNTIME_RESOURCE_VAL)) + session_policy_s3_resource_flag = true; + if (session_policy_s3_exist_tag && session_policy_s3_resource_flag) + break; + } + } + + has_existing_obj_tag = iam_policy_s3_exist_tag || identity_policy_s3_exist_tag || session_policy_s3_exist_tag; + has_resource_tag = iam_policy_s3_resource_tag || identity_policy_s3_resource_tag || session_policy_s3_resource_flag; + return make_tuple(has_existing_obj_tag, has_resource_tag); +} + +static std::tuple rgw_check_policy_condition(const DoutPrefixProvider *dpp, struct req_state* s, bool check_obj_exist_tag=true) { + return rgw_check_policy_condition(dpp, s->iam_policy, s->iam_user_policies, s->session_policies, check_obj_exist_tag); +} + static void rgw_add_grant_to_iam_environment(rgw::IAM::Environment& e, struct req_state *s){ using header_pair_t = std::pair ; @@ -918,6 +1044,10 @@ int RGWGetObj::verify_permission(optional_yield y) s->object->set_prefetch_data(s->obj_ctx); } + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (torrent.get_flag()) { if (s->object->get_instance().empty()) { action = rgw::IAM::s3GetObjectTorrent; @@ -930,14 +1060,6 @@ int RGWGetObj::verify_permission(optional_yield y) } else { action = rgw::IAM::s3GetObjectVersion; } - if (s->iam_policy && s->iam_policy->has_partial_conditional(S3_EXISTING_OBJTAG)) - rgw_iam_add_existing_objtags(this, store, s, action); - if (! s->iam_user_policies.empty()) { - for (auto& user_policy : s->iam_user_policies) { - if (user_policy.has_partial_conditional(S3_EXISTING_OBJTAG)) - rgw_iam_add_existing_objtags(this, store, s, action); - } - } } if (!verify_object_permission(this, s, action)) { @@ -977,18 +1099,10 @@ int RGWGetObjTags::verify_permission(optional_yield y) auto iam_action = s->object->get_instance().empty()? rgw::IAM::s3GetObjectTagging: rgw::IAM::s3GetObjectVersionTagging; - // TODO since we are parsing the bl now anyway, we probably change - // the send_response function to accept RGWObjTag instead of a bl - if (s->iam_policy && s->iam_policy->has_partial_conditional(S3_EXISTING_OBJTAG)){ - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - if (! s->iam_user_policies.empty()) { - for (auto& user_policy : s->iam_user_policies) { - if (user_policy.has_partial_conditional(S3_EXISTING_OBJTAG)) { - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - } - } + + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); if (!verify_object_permission(this, s,iam_action)) return -EACCES; @@ -1028,16 +1142,12 @@ int RGWPutObjTags::verify_permission(optional_yield y) rgw::IAM::s3PutObjectTagging: rgw::IAM::s3PutObjectVersionTagging; - if(s->iam_policy && s->iam_policy->has_partial_conditional(S3_EXISTING_OBJTAG)){ - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - if (! s->iam_user_policies.empty()) { - for (auto& user_policy : s->iam_user_policies) { - if (user_policy.has_partial_conditional(S3_EXISTING_OBJTAG)) { - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - } - } + //Using buckets tags for authorization makes more sense. + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, true); + if (has_s3_existing_tag) + rgw_iam_add_objtags(this, s, true, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); if (!verify_object_permission(this, s,iam_action)) return -EACCES; return 0; @@ -1074,18 +1184,11 @@ int RGWDeleteObjTags::verify_permission(optional_yield y) rgw::IAM::s3DeleteObjectTagging: rgw::IAM::s3DeleteObjectVersionTagging; - if (s->iam_policy && s->iam_policy->has_partial_conditional(S3_EXISTING_OBJTAG)){ - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - if (! s->iam_user_policies.empty()) { - for (auto& user_policy : s->iam_user_policies) { - if (user_policy.has_partial_conditional(S3_EXISTING_OBJTAG)) { - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - } - } - if (!verify_object_permission(this, s, iam_action)) - return -EACCES; + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (!verify_object_permission(this, s, iam_action)) + return -EACCES; } return 0; } @@ -1100,6 +1203,9 @@ void RGWDeleteObjTags::execute(optional_yield y) int RGWGetBucketTags::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); if (!verify_bucket_permission(this, s, rgw::IAM::s3GetBucketTagging)) { return -EACCES; @@ -1126,6 +1232,10 @@ void RGWGetBucketTags::execute(optional_yield y) } int RGWPutBucketTags::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketTagging); } @@ -1156,6 +1266,10 @@ void RGWDeleteBucketTags::pre_exec() int RGWDeleteBucketTags::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketTagging); } @@ -1183,6 +1297,10 @@ void RGWDeleteBucketTags::execute(optional_yield y) int RGWGetBucketReplication::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3GetReplicationConfiguration)) { return -EACCES; } @@ -1201,6 +1319,9 @@ void RGWGetBucketReplication::execute(optional_yield y) } int RGWPutBucketReplication::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutReplicationConfiguration); } @@ -1242,6 +1363,10 @@ void RGWDeleteBucketReplication::pre_exec() int RGWDeleteBucketReplication::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3DeleteReplicationConfiguration); } @@ -2521,6 +2646,10 @@ void RGWStatAccount::execute(optional_yield y) int RGWGetBucketVersioning::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3GetBucketVersioning); } @@ -2543,6 +2672,10 @@ void RGWGetBucketVersioning::execute(optional_yield y) int RGWSetBucketVersioning::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketVersioning); } @@ -2637,6 +2770,10 @@ void RGWSetBucketVersioning::execute(optional_yield y) int RGWGetBucketWebsite::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3GetBucketWebsite); } @@ -2654,6 +2791,10 @@ void RGWGetBucketWebsite::execute(optional_yield y) int RGWSetBucketWebsite::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketWebsite); } @@ -2696,6 +2837,10 @@ void RGWSetBucketWebsite::execute(optional_yield y) int RGWDeleteBucketWebsite::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3DeleteBucketWebsite); } @@ -2734,6 +2879,10 @@ void RGWDeleteBucketWebsite::execute(optional_yield y) int RGWStatBucket::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + // This (a HEAD request on a bucket) is governed by the s3:ListBucket permission. if (!verify_bucket_permission(this, s, rgw::IAM::s3ListBucket)) { return -EACCES; @@ -2775,6 +2924,10 @@ int RGWListBucket::verify_permission(optional_yield y) s->env.emplace("s3:max-keys", std::to_string(max)); + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, list_versions ? @@ -2842,11 +2995,19 @@ void RGWListBucket::execute(optional_yield y) int RGWGetBucketLogging::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3GetBucketLogging); } int RGWGetBucketLocation::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3GetBucketLocation); } @@ -3290,6 +3451,10 @@ void RGWCreateBucket::execute(optional_yield y) int RGWDeleteBucket::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3DeleteBucket)) { return -EACCES; } @@ -3487,7 +3652,11 @@ int RGWPutObj::verify_permission(optional_yield y) /* admin request overrides permission checks */ if (! s->auth.identity->is_admin_of(cs_acl.get_owner().get_id())) { - if (policy || ! s->iam_user_policies.empty()) { + if (policy || ! s->iam_user_policies.empty() || !s->session_policies.empty()) { + //add source object tags for permission evaluation + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, policy, s->iam_user_policies, s->session_policies); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, cs_object.get(), has_s3_existing_tag, has_s3_resource_tag); auto usr_policy_res = Effect::Pass; for (auto& user_policy : s->iam_user_policies) { if (usr_policy_res = user_policy.eval(s->env, *s->auth.identity, @@ -3514,6 +3683,7 @@ int RGWPutObj::verify_permission(optional_yield y) RGW_PERM_READ)) { return -EACCES; } + rgw_iam_remove_objtags(this, s, cs_object.get(), has_s3_existing_tag, has_s3_resource_tag); } else if (!cs_acl.verify_permission(this, *s->auth.identity, s->perm_mask, RGW_PERM_READ)) { return -EACCES; @@ -3534,7 +3704,7 @@ int RGWPutObj::verify_permission(optional_yield y) return op_ret; } - if (s->iam_policy || ! s->iam_user_policies.empty()) { + if (s->iam_policy || ! s->iam_user_policies.empty() || !s->session_policies.empty()) { rgw_add_grant_to_iam_environment(s->env, s); rgw_add_to_iam_environment(s->env, "s3:x-amz-acl", s->canned_acl); @@ -3563,6 +3733,11 @@ int RGWPutObj::verify_permission(optional_yield y) /* Object needs a bucket from this point */ s->object->set_bucket(s->bucket.get()); + // Add bucket tags for authorization + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + auto identity_policy_res = eval_identity_or_session_policies(s->iam_user_policies, s->env, boost::none, rgw::IAM::s3PutObject, @@ -4741,6 +4916,11 @@ int RGWDeleteObj::verify_permission(optional_yield y) if (op_ret) { return op_ret; } + + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (s->iam_policy || ! s->iam_user_policies.empty() || ! s->session_policies.empty()) { if (s->bucket->get_info().obj_lock_enabled() && bypass_governance_mode) { auto r = eval_identity_or_session_policies(s->iam_user_policies, s->env, boost::none, @@ -5071,6 +5251,10 @@ int RGWCopyObj::verify_permission(optional_yield y) /* admin request overrides permission checks */ if (!s->auth.identity->is_admin_of(src_acl.get_owner().get_id())) { if (src_policy || ! s->iam_user_policies.empty() || !s->session_policies.empty()) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, src_policy, s->iam_user_policies, s->session_policies); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, src_object.get(), has_s3_existing_tag, has_s3_resource_tag); + auto identity_policy_res = eval_identity_or_session_policies(s->iam_user_policies, s->env, boost::none, src_object->get_instance().empty() ? @@ -5125,6 +5309,10 @@ int RGWCopyObj::verify_permission(optional_yield y) RGW_PERM_READ)) { return -EACCES; } + //remove src object tags as it may interfere with policy evaluation of destination obj + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_remove_objtags(this, s, src_object.get(), has_s3_existing_tag, has_s3_resource_tag); + } else if (!src_acl.verify_permission(this, *s->auth.identity, s->perm_mask, RGW_PERM_READ)) { @@ -5172,6 +5360,11 @@ int RGWCopyObj::verify_permission(optional_yield y) /* admin request overrides permission checks */ if (! s->auth.identity->is_admin_of(dest_policy.get_owner().get_id())){ if (dest_iam_policy != boost::none || ! s->iam_user_policies.empty() || !s->session_policies.empty()) { + //Add destination bucket tags for authorization + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, dest_iam_policy, s->iam_user_policies, s->session_policies); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s, dest_bucket.get()); + rgw_add_to_iam_environment(s->env, "s3:x-amz-copy-source", copy_source); if (md_directive) rgw_add_to_iam_environment(s->env, "s3:x-amz-metadata-directive", @@ -5394,26 +5587,20 @@ void RGWCopyObj::execute(optional_yield y) int RGWGetACLs::verify_permission(optional_yield y) { bool perm; + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); if (!rgw::sal::RGWObject::empty(s->object.get())) { auto iam_action = s->object->get_instance().empty() ? rgw::IAM::s3GetObjectAcl : rgw::IAM::s3GetObjectVersionAcl; - - if (s->iam_policy && s->iam_policy->has_partial_conditional(S3_EXISTING_OBJTAG)){ - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - if (! s->iam_user_policies.empty()) { - for (auto& user_policy : s->iam_user_policies) { - if (user_policy.has_partial_conditional(S3_EXISTING_OBJTAG)) { - rgw_iam_add_existing_objtags(this, store, s, iam_action); - } - } - } + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); perm = verify_object_permission(this, s, iam_action); } else { if (!s->bucket_exists) { return -ERR_NO_SUCH_BUCKET; } + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); perm = verify_bucket_permission(this, s, rgw::IAM::s3GetBucketAcl); } if (!perm) @@ -5449,9 +5636,10 @@ int RGWPutACLs::verify_permission(optional_yield y) rgw_add_grant_to_iam_environment(s->env, s); if (!rgw::sal::RGWObject::empty(s->object.get())) { auto iam_action = s->object->get_instance().empty() ? rgw::IAM::s3PutObjectAcl : rgw::IAM::s3PutObjectVersionAcl; - op_ret = rgw_iam_add_existing_objtags(this, store, s, iam_action); + op_ret = rgw_iam_add_objtags(this, s, true, true); perm = verify_object_permission(this, s, iam_action); } else { + op_ret = rgw_iam_add_buckettags(this, s); perm = verify_bucket_permission(this, s, rgw::IAM::s3PutBucketAcl); } if (!perm) @@ -5462,6 +5650,10 @@ int RGWPutACLs::verify_permission(optional_yield y) int RGWGetLC::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + bool perm; perm = verify_bucket_permission(this, s, rgw::IAM::s3GetLifecycleConfiguration); if (!perm) @@ -5472,6 +5664,10 @@ int RGWGetLC::verify_permission(optional_yield y) int RGWPutLC::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + bool perm; perm = verify_bucket_permission(this, s, rgw::IAM::s3PutLifecycleConfiguration); if (!perm) @@ -5482,6 +5678,10 @@ int RGWPutLC::verify_permission(optional_yield y) int RGWDeleteLC::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + bool perm; perm = verify_bucket_permission(this, s, rgw::IAM::s3PutLifecycleConfiguration); if (!perm) @@ -5758,6 +5958,10 @@ void RGWDeleteLC::execute(optional_yield y) int RGWGetCORS::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3GetBucketCORS); } @@ -5776,6 +5980,10 @@ void RGWGetCORS::execute(optional_yield y) int RGWPutCORS::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketCORS); } @@ -5802,6 +6010,10 @@ void RGWPutCORS::execute(optional_yield y) int RGWDeleteCORS::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + // No separate delete permission return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketCORS); } @@ -5893,6 +6105,10 @@ void RGWOptionsCORS::execute(optional_yield y) int RGWGetRequestPayment::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3GetBucketRequestPayment); } @@ -5908,6 +6124,10 @@ void RGWGetRequestPayment::execute(optional_yield y) int RGWSetRequestPayment::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketRequestPayment); } @@ -5942,6 +6162,10 @@ void RGWSetRequestPayment::execute(optional_yield y) int RGWInitMultipart::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (s->iam_policy || ! s->iam_user_policies.empty() || !s->session_policies.empty()) { auto identity_policy_res = eval_identity_or_session_policies(s->iam_user_policies, s->env, boost::none, @@ -6072,6 +6296,10 @@ void RGWInitMultipart::execute(optional_yield y) int RGWCompleteMultipart::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (s->iam_policy || ! s->iam_user_policies.empty() || ! s->session_policies.empty()) { auto identity_policy_res = eval_identity_or_session_policies(s->iam_user_policies, s->env, boost::none, @@ -6487,6 +6715,10 @@ void RGWCompleteMultipart::complete() int RGWAbortMultipart::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (s->iam_policy || ! s->iam_user_policies.empty() || !s->session_policies.empty()) { auto identity_policy_res = eval_identity_or_session_policies(s->iam_user_policies, s->env, boost::none, @@ -6576,6 +6808,10 @@ void RGWAbortMultipart::execute(optional_yield y) int RGWListMultipart::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (!verify_object_permission(this, s, rgw::IAM::s3ListMultipartUploadParts)) return -EACCES; @@ -6609,6 +6845,10 @@ void RGWListMultipart::execute(optional_yield y) int RGWListBucketMultiparts::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3ListBucketMultipartUploads)) @@ -6683,6 +6923,10 @@ int RGWDeleteMultiObj::verify_permission(optional_yield y) return op_ret; } + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (s->iam_policy || ! s->iam_user_policies.empty() || ! s->session_policies.empty()) { if (s->bucket->get_info().obj_lock_enabled() && bypass_governance_mode) { auto r = eval_identity_or_session_policies(s->iam_user_policies, s->env, boost::none, @@ -7708,6 +7952,10 @@ int RGWGetAttrs::verify_permission(optional_yield y) { s->object->set_atomic(s->obj_ctx); + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + auto iam_action = s->object->get_instance().empty() ? rgw::IAM::s3GetObject : rgw::IAM::s3GetObjectVersion; @@ -8019,6 +8267,10 @@ void RGWPutBucketPolicy::send_response() int RGWPutBucketPolicy::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3PutBucketPolicy)) { return -EACCES; } @@ -8084,6 +8336,10 @@ void RGWGetBucketPolicy::send_response() int RGWGetBucketPolicy::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3GetBucketPolicy)) { return -EACCES; } @@ -8125,6 +8381,10 @@ void RGWDeleteBucketPolicy::send_response() int RGWDeleteBucketPolicy::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3DeleteBucketPolicy)) { return -EACCES; } @@ -8156,6 +8416,10 @@ void RGWPutBucketObjectLock::pre_exec() int RGWPutBucketObjectLock::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketObjectLockConfiguration); } @@ -8218,6 +8482,10 @@ void RGWGetBucketObjectLock::pre_exec() int RGWGetBucketObjectLock::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + return verify_bucket_owner_or_policy(s, rgw::IAM::s3GetBucketObjectLockConfiguration); } @@ -8231,6 +8499,10 @@ void RGWGetBucketObjectLock::execute(optional_yield y) int RGWPutObjRetention::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (!verify_object_permission(this, s, rgw::IAM::s3PutObjectRetention)) { return -EACCES; } @@ -8330,6 +8602,10 @@ void RGWPutObjRetention::execute(optional_yield y) int RGWGetObjRetention::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (!verify_object_permission(this, s, rgw::IAM::s3GetObjectRetention)) { return -EACCES; } @@ -8375,6 +8651,10 @@ void RGWGetObjRetention::execute(optional_yield y) int RGWPutObjLegalHold::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (!verify_object_permission(this, s, rgw::IAM::s3PutObjectLegalHold)) { return -EACCES; } @@ -8426,6 +8706,10 @@ void RGWPutObjLegalHold::execute(optional_yield y) { int RGWGetObjLegalHold::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s); + if (has_s3_existing_tag || has_s3_resource_tag) + rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag); + if (!verify_object_permission(this, s, rgw::IAM::s3GetObjectLegalHold)) { return -EACCES; } @@ -8476,6 +8760,10 @@ void RGWGetClusterStat::execute(optional_yield y) int RGWGetBucketPolicyStatus::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3GetBucketPolicyStatus)) { return -EACCES; } @@ -8490,6 +8778,10 @@ void RGWGetBucketPolicyStatus::execute(optional_yield y) int RGWPutBucketPublicAccessBlock::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3PutBucketPublicAccessBlock)) { return -EACCES; } @@ -8549,6 +8841,10 @@ void RGWPutBucketPublicAccessBlock::execute(optional_yield y) int RGWGetBucketPublicAccessBlock::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3GetBucketPolicy)) { return -EACCES; } @@ -8589,6 +8885,10 @@ void RGWDeleteBucketPublicAccessBlock::send_response() int RGWDeleteBucketPublicAccessBlock::verify_permission(optional_yield y) { + auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false); + if (has_s3_resource_tag) + rgw_iam_add_buckettags(this, s); + if (!verify_bucket_permission(this, s, rgw::IAM::s3PutBucketPublicAccessBlock)) { return -EACCES; }