Skip to content

Commit 49a44ce

Browse files
authored
Merge pull request ceph#60685 from clwluvw/data-sync-perm
rgw: respect policies in data sync in user mode Reviewed-by: Adam Emerson <[email protected]>
2 parents 6fd292f + b8a5917 commit 49a44ce

File tree

6 files changed

+76
-78
lines changed

6 files changed

+76
-78
lines changed

src/rgw/driver/rados/rgw_data_sync.cc

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,6 +2617,7 @@ class RGWUserPermHandler {
26172617
rgw::IAM::Environment env;
26182618
std::unique_ptr<rgw::auth::Identity> identity;
26192619
RGWAccessControlPolicy user_acl;
2620+
std::vector<rgw::IAM::Policy> user_policies;
26202621
};
26212622

26222623
std::shared_ptr<_info> info;
@@ -2644,7 +2645,7 @@ class RGWUserPermHandler {
26442645
}
26452646

26462647
auto result = rgw::auth::transform_old_authinfo(
2647-
sync_env->dpp, null_yield, sync_env->driver, user.get());
2648+
sync_env->dpp, null_yield, sync_env->driver, user.get(), &info->user_policies);
26482649
if (!result) {
26492650
return result.error();
26502651
}
@@ -2679,16 +2680,15 @@ class RGWUserPermHandler {
26792680
std::shared_ptr<_info> info;
26802681
RGWAccessControlPolicy bucket_acl;
26812682
std::optional<perm_state> ps;
2683+
boost::optional<rgw::IAM::Policy> bucket_policy;
26822684
public:
26832685
Bucket() {}
26842686

26852687
int init(RGWUserPermHandler *handler,
26862688
const RGWBucketInfo& bucket_info,
26872689
const map<string, bufferlist>& bucket_attrs);
26882690

2689-
bool verify_bucket_permission(int perm);
2690-
bool verify_object_permission(const map<string, bufferlist>& obj_attrs,
2691-
int perm);
2691+
bool verify_bucket_permission(const rgw_obj_key& obj_key, const uint64_t op);
26922692
};
26932693

26942694
static int policy_from_attrs(CephContext *cct,
@@ -2728,6 +2728,14 @@ int RGWUserPermHandler::Bucket::init(RGWUserPermHandler *handler,
27282728
return r;
27292729
}
27302730

2731+
// load bucket policy
2732+
try {
2733+
bucket_policy = get_iam_policy_from_attr(sync_env->cct, bucket_attrs, bucket_info.bucket.tenant);
2734+
} catch (const std::exception& e) {
2735+
ldpp_dout(sync_env->dpp, 0) << "ERROR: reading IAM Policy: " << e.what() << dendl;
2736+
return -EACCES;
2737+
}
2738+
27312739
ps.emplace(sync_env->cct,
27322740
info->env,
27332741
info->identity.get(),
@@ -2740,36 +2748,40 @@ int RGWUserPermHandler::Bucket::init(RGWUserPermHandler *handler,
27402748
return 0;
27412749
}
27422750

2743-
bool RGWUserPermHandler::Bucket::verify_bucket_permission(int perm)
2744-
{
2745-
return verify_bucket_permission_no_policy(sync_env->dpp,
2746-
&(*ps),
2747-
info->user_acl,
2748-
bucket_acl,
2749-
perm);
2750-
}
2751-
2752-
bool RGWUserPermHandler::Bucket::verify_object_permission(const map<string, bufferlist>& obj_attrs,
2753-
int perm)
2751+
bool RGWUserPermHandler::Bucket::verify_bucket_permission(const rgw_obj_key& obj_key, const uint64_t op)
27542752
{
2755-
RGWAccessControlPolicy obj_acl;
2756-
2757-
int r = policy_from_attrs(sync_env->cct, obj_attrs, &obj_acl);
2758-
if (r < 0) {
2759-
return r;
2760-
}
2761-
2762-
return verify_bucket_permission_no_policy(sync_env->dpp,
2763-
&(*ps),
2764-
bucket_acl,
2765-
obj_acl,
2766-
perm);
2753+
const rgw_obj obj(ps->bucket_info.bucket, obj_key);
2754+
const auto arn = rgw::ARN(obj);
2755+
2756+
if (ps->identity->get_account()) {
2757+
const bool account_root = (ps->identity->get_identity_type() == TYPE_ROOT);
2758+
if (!ps->identity->is_owner_of(bucket_acl.get_owner().id)) {
2759+
ldpp_dout(sync_env->dpp, 4) << "cross-account request for bucket owner "
2760+
<< bucket_acl.get_owner().id << " != " << ps->identity->get_aclowner().id << dendl;
2761+
// cross-account requests evaluate the identity-based policies separately
2762+
// from the resource-based policies and require Allow from both
2763+
return ::verify_bucket_permission(sync_env->dpp, &(*ps), arn, account_root, {}, {}, {},
2764+
info->user_policies, {}, op)
2765+
&& ::verify_bucket_permission(sync_env->dpp, &(*ps), arn, false, info->user_acl,
2766+
bucket_acl, bucket_policy, {}, {}, op);
2767+
} else {
2768+
// don't consult acls for same-account access. require an Allow from
2769+
// either identity- or resource-based policy
2770+
return ::verify_bucket_permission(sync_env->dpp, &(*ps), arn, account_root, {}, {},
2771+
bucket_policy, info->user_policies,
2772+
{}, op);
2773+
}
2774+
}
2775+
constexpr bool account_root = false;
2776+
return ::verify_bucket_permission(sync_env->dpp, &(*ps), arn, account_root,
2777+
info->user_acl, bucket_acl,
2778+
bucket_policy, info->user_policies,
2779+
{}, op);
27672780
}
27682781

27692782
class RGWFetchObjFilter_Sync : public RGWFetchObjFilter_Default {
27702783
rgw_bucket_sync_pipe sync_pipe;
27712784

2772-
std::shared_ptr<RGWUserPermHandler::Bucket> bucket_perms;
27732785
std::optional<rgw_sync_pipe_dest_params> verify_dest_params;
27742786

27752787
std::optional<ceph::real_time> mtime;
@@ -2782,10 +2794,8 @@ class RGWFetchObjFilter_Sync : public RGWFetchObjFilter_Default {
27822794

27832795
public:
27842796
RGWFetchObjFilter_Sync(rgw_bucket_sync_pipe& _sync_pipe,
2785-
std::shared_ptr<RGWUserPermHandler::Bucket>& _bucket_perms,
27862797
std::optional<rgw_sync_pipe_dest_params>&& _verify_dest_params,
27872798
std::shared_ptr<bool>& _need_retry) : sync_pipe(_sync_pipe),
2788-
bucket_perms(_bucket_perms),
27892799
verify_dest_params(std::move(_verify_dest_params)),
27902800
need_retry(_need_retry) {
27912801
*need_retry = false;
@@ -2852,12 +2862,6 @@ int RGWFetchObjFilter_Sync::filter(CephContext *cct,
28522862
*poverride_owner = acl_translation_owner;
28532863
}
28542864
}
2855-
if (params.mode == rgw_sync_pipe_params::MODE_USER) {
2856-
if (!bucket_perms->verify_object_permission(obj_attrs, RGW_PERM_READ)) {
2857-
ldout(cct, 0) << "ERROR: " << __func__ << ": permission check failed: user not allowed to fetch object" << dendl;
2858-
return -EPERM;
2859-
}
2860-
}
28612865

28622866
if (!dest_placement_rule &&
28632867
params.dest.storage_class) {
@@ -2900,7 +2904,6 @@ class RGWObjFetchCR : public RGWCoroutine {
29002904
rgw_sync_pipe_params::Mode param_mode;
29012905

29022906
std::optional<RGWUserPermHandler> user_perms;
2903-
std::shared_ptr<RGWUserPermHandler::Bucket> source_bucket_perms;
29042907
RGWUserPermHandler::Bucket dest_bucket_perms;
29052908

29062909
std::optional<rgw_sync_pipe_dest_params> dest_params;
@@ -3016,33 +3019,22 @@ class RGWObjFetchCR : public RGWCoroutine {
30163019
return set_cr_error(retcode);
30173020
}
30183021

3019-
if (!dest_bucket_perms.verify_bucket_permission(RGW_PERM_WRITE)) {
3022+
if (!dest_bucket_perms.verify_bucket_permission(dest_key.value_or(key), rgw::IAM::s3PutObject)) {
30203023
ldout(cct, 0) << "ERROR: " << __func__ << ": permission check failed: user not allowed to write into bucket (bucket=" << sync_pipe.info.dest_bucket.get_key() << ")" << dendl;
30213024
return -EPERM;
30223025
}
3023-
3024-
/* init source bucket permission structure */
3025-
source_bucket_perms = make_shared<RGWUserPermHandler::Bucket>();
3026-
r = user_perms->init_bucket(sync_pipe.source_bucket_info,
3027-
sync_pipe.source_bucket_attrs,
3028-
source_bucket_perms.get());
3029-
if (r < 0) {
3030-
ldout(cct, 20) << "ERROR: " << __func__ << ": failed to init bucket perms manager for uid=" << *param_user << " bucket=" << sync_pipe.source_bucket_info.bucket.get_key() << dendl;
3031-
return set_cr_error(retcode);
3032-
}
30333026
}
30343027

30353028
yield {
30363029
if (!need_retry) {
30373030
need_retry = make_shared<bool>();
30383031
}
30393032
auto filter = make_shared<RGWFetchObjFilter_Sync>(sync_pipe,
3040-
source_bucket_perms,
30413033
std::move(dest_params),
30423034
need_retry);
30433035

30443036
call(new RGWFetchRemoteObjCR(sync_env->async_rados, sync_env->driver, sc->source_zone,
3045-
nullopt,
3037+
param_user,
30463038
sync_pipe.source_bucket_info.bucket,
30473039
std::nullopt, sync_pipe.dest_bucket_info,
30483040
key, dest_key, versioned_epoch,
@@ -4528,7 +4520,7 @@ class RGWBucketSyncSingleEntryCR : public RGWCoroutine {
45284520
}
45294521
tn->set_resource_name(SSTR(bucket_str_noinstance(bs.bucket) << "/" << key));
45304522
}
4531-
if (retcode == -ERR_PRECONDITION_FAILED) {
4523+
if (retcode == -ERR_PRECONDITION_FAILED || retcode == -EPERM) {
45324524
pretty_print(sc->env, "Skipping object s3://{}/{} in sync from zone {}\n",
45334525
bs.bucket.name, key, zone_name);
45344526
set_status("Skipping object sync: precondition failed (object contains newer change or policy doesn't allow sync)");

src/rgw/rgw_auth.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ static auto transform_old_authinfo(const RGWUserInfo& user,
313313
auto transform_old_authinfo(const DoutPrefixProvider* dpp,
314314
optional_yield y,
315315
sal::Driver* driver,
316-
sal::User* user)
316+
sal::User* user,
317+
std::vector<IAM::Policy>* policies_)
317318
-> tl::expected<std::unique_ptr<Identity>, int>
318319
{
319320
const RGWUserInfo& info = user->get_info();
@@ -328,6 +329,9 @@ auto transform_old_authinfo(const DoutPrefixProvider* dpp,
328329
return tl::unexpected(r);
329330
}
330331

332+
if (policies_) { // return policies to caller if requested
333+
*policies_ = policies;
334+
}
331335
return transform_old_authinfo(info, std::move(account), std::move(policies));
332336
}
333337

src/rgw/rgw_auth.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ inline std::ostream& operator<<(std::ostream& out,
105105
auto transform_old_authinfo(const DoutPrefixProvider* dpp,
106106
optional_yield y,
107107
sal::Driver* driver,
108-
sal::User* user)
108+
sal::User* user,
109+
std::vector<IAM::Policy>* policies_ = nullptr)
109110
-> tl::expected<std::unique_ptr<Identity>, int>;
110111

111112
// Load the user account and all user/group policies. May throw

src/rgw/rgw_common.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,3 +3206,14 @@ void RGWObjVersionTracker::generate_new_write_ver(CephContext *cct)
32063206
append_rand_alpha(cct, write_version.tag, write_version.tag, TAG_LEN);
32073207
}
32083208

3209+
boost::optional<rgw::IAM::Policy>
3210+
get_iam_policy_from_attr(CephContext* cct,
3211+
const std::map<std::string, bufferlist>& attrs,
3212+
const std::string& tenant)
3213+
{
3214+
if (auto i = attrs.find(RGW_ATTR_IAM_POLICY); i != attrs.end()) {
3215+
return Policy(cct, &tenant, i->second.to_str(), false);
3216+
} else {
3217+
return boost::none;
3218+
}
3219+
}

src/rgw/rgw_common.h

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,18 +1745,6 @@ rgw::IAM::Effect evaluate_iam_policies(
17451745
const std::vector<rgw::IAM::Policy>& identity_policies,
17461746
const std::vector<rgw::IAM::Policy>& session_policies);
17471747

1748-
bool verify_user_permission(const DoutPrefixProvider* dpp,
1749-
req_state * const s,
1750-
const RGWAccessControlPolicy& user_acl,
1751-
const std::vector<rgw::IAM::Policy>& user_policies,
1752-
const std::vector<rgw::IAM::Policy>& session_policies,
1753-
const rgw::ARN& res,
1754-
const uint64_t op,
1755-
bool mandatory_policy=true);
1756-
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
1757-
req_state * const s,
1758-
const RGWAccessControlPolicy& user_acl,
1759-
const int perm);
17601748
bool verify_user_permission(const DoutPrefixProvider* dpp,
17611749
req_state * const s,
17621750
const rgw::ARN& res,
@@ -1765,6 +1753,16 @@ bool verify_user_permission(const DoutPrefixProvider* dpp,
17651753
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
17661754
req_state * const s,
17671755
int perm);
1756+
bool verify_bucket_permission(const DoutPrefixProvider* dpp,
1757+
struct perm_state_base * const s,
1758+
const rgw::ARN& arn,
1759+
bool account_root,
1760+
const RGWAccessControlPolicy& user_acl,
1761+
const RGWAccessControlPolicy& bucket_acl,
1762+
const boost::optional<rgw::IAM::Policy>& bucket_policy,
1763+
const std::vector<rgw::IAM::Policy>& identity_policies,
1764+
const std::vector<rgw::IAM::Policy>& session_policies,
1765+
const uint64_t op);
17681766
bool verify_bucket_permission(
17691767
const DoutPrefixProvider* dpp,
17701768
req_state * const s,
@@ -2012,3 +2010,8 @@ struct AioCompletionDeleter {
20122010
void operator()(librados::AioCompletion* c) { c->release(); }
20132011
};
20142012
using aio_completion_ptr = std::unique_ptr<librados::AioCompletion, AioCompletionDeleter>;
2013+
2014+
extern boost::optional<rgw::IAM::Policy>
2015+
get_iam_policy_from_attr(CephContext* cct,
2016+
const std::map<std::string, bufferlist>& attrs,
2017+
const std::string& tenant);

src/rgw/rgw_op.cc

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -331,19 +331,6 @@ static int get_obj_policy_from_attr(const DoutPrefixProvider *dpp,
331331
return ret;
332332
}
333333

334-
335-
static boost::optional<Policy>
336-
get_iam_policy_from_attr(CephContext* cct,
337-
const map<string, bufferlist>& attrs,
338-
const string& tenant)
339-
{
340-
if (auto i = attrs.find(RGW_ATTR_IAM_POLICY); i != attrs.end()) {
341-
return Policy(cct, &tenant, i->second.to_str(), false);
342-
} else {
343-
return none;
344-
}
345-
}
346-
347334
static boost::optional<PublicAccessBlockConfiguration>
348335
get_public_access_conf_from_attr(const map<string, bufferlist>& attrs)
349336
{

0 commit comments

Comments
 (0)