From fd0da48c3ff80fb920b4bb6f3ee91bc274afc3b7 Mon Sep 17 00:00:00 2001 From: Pritha Srivastava Date: Fri, 7 May 2021 18:36:23 +0530 Subject: [PATCH] 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 --- src/rgw/rgw_iam_policy.h | 24 +++ src/rgw/rgw_op.cc | 426 +++++++++++++++++++++++++++++++++------ 2 files changed, 387 insertions(+), 63 deletions(-) diff --git a/src/rgw/rgw_iam_policy.h b/src/rgw/rgw_iam_policy.h index e5ab4c7092262..b91718789f74c 100644 --- a/src/rgw/rgw_iam_policy.h +++ b/src/rgw/rgw_iam_policy.h @@ -447,6 +447,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); @@ -520,6 +529,16 @@ struct Policy { return false; } + 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()); } @@ -527,6 +546,11 @@ struct Policy { bool has_partial_conditional(const std::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 <<(std::ostream& m, const Policy& p); diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index b3f2f85c2dc8c..64f4fc0e64030 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -98,6 +98,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) { @@ -674,6 +676,56 @@ int rgw_build_object_policies(const DoutPrefixProvider *dpp, rgw::sal::Store* st return ret; } +static int rgw_iam_remove_objtags(const DoutPrefixProvider *dpp, struct req_state* s, rgw::sal::Object* 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::Attrs 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 @@ -681,7 +733,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(); @@ -692,24 +744,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::Store* 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::Object* 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::Attrs attrs = s->object->get_attrs(); + rgw::sal::Attrs 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::Object::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::Bucket* bucket) { + rgw::sal::Attrs 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 ; @@ -837,6 +963,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; @@ -849,14 +979,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)) { @@ -898,18 +1020,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; @@ -949,16 +1063,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; @@ -995,18 +1105,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; } @@ -1021,6 +1124,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; @@ -1047,6 +1153,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); } @@ -1077,6 +1187,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); } @@ -1104,6 +1218,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; } @@ -1122,6 +1240,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); } @@ -1163,6 +1284,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); } @@ -2436,6 +2561,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); } @@ -2458,6 +2587,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); } @@ -2552,6 +2685,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); } @@ -2569,6 +2706,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); } @@ -2611,6 +2752,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); } @@ -2649,6 +2794,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; @@ -2690,6 +2839,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 ? @@ -2757,11 +2910,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); } @@ -3176,6 +3337,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; } @@ -3388,7 +3553,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, @@ -3415,6 +3584,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; @@ -3435,7 +3605,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); @@ -3464,6 +3634,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, @@ -4617,6 +4792,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, @@ -4952,6 +5132,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() ? @@ -5006,6 +5190,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)) { @@ -5045,6 +5233,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", @@ -5279,26 +5472,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::Object::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) @@ -5334,9 +5521,10 @@ int RGWPutACLs::verify_permission(optional_yield y) rgw_add_grant_to_iam_environment(s->env, s); if (!rgw::sal::Object::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) @@ -5347,6 +5535,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) @@ -5357,6 +5549,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) @@ -5367,6 +5563,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) @@ -5639,6 +5839,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); } @@ -5657,6 +5861,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); } @@ -5683,6 +5891,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); } @@ -5774,6 +5986,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); } @@ -5789,6 +6005,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); } @@ -5823,6 +6043,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, @@ -5927,6 +6151,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, @@ -6172,6 +6400,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, @@ -6254,6 +6486,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; @@ -6294,6 +6530,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)) @@ -6357,6 +6597,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, @@ -7350,6 +7594,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; @@ -7647,6 +7895,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; } @@ -7712,6 +7964,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; } @@ -7753,6 +8009,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; } @@ -7784,6 +8044,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); } @@ -7846,6 +8110,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); } @@ -7859,6 +8127,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; } @@ -7958,6 +8230,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; } @@ -8003,6 +8279,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; } @@ -8054,6 +8334,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; } @@ -8104,6 +8388,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; } @@ -8118,6 +8406,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; } @@ -8177,6 +8469,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; } @@ -8217,6 +8513,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; } -- 2.39.5