#include "rgw_cr_rest.h"
#include "rgw_rest_conn.h"
#include "rgw_rados.h"
+#include "rgw_data_sync.h"
#include "services/svc_zone.h"
#include "services/svc_zone_utils.h"
stat_dest_obj,
source_trace_entry,
&zones_trace,
- &bytes_transferred);
+ &bytes_transferred,
+ keep_tags);
if (r < 0) {
ldpp_dout(dpp, 0) << "store->fetch_remote_obj() returned r=" << r << dendl;
#include "rgw_coroutine.h"
#include "rgw_sal.h"
#include "rgw_sal_rados.h"
+#include "rgw_bucket_sync.h"
#include "common/WorkQueue.h"
#include "common/Throttle.h"
rgw_zone_set zones_trace;
PerfCounters* counters;
const DoutPrefixProvider *dpp;
+ bool keep_tags;
protected:
int _send_request(const DoutPrefixProvider *dpp) override;
const rgw_zone_set_entry& source_trace_entry,
rgw_zone_set *_zones_trace,
PerfCounters* counters,
- const DoutPrefixProvider *dpp)
+ const DoutPrefixProvider *dpp,
+ bool _keep_tags)
: RGWAsyncRadosRequest(caller, cn), store(_store),
source_zone(_source_zone),
user_id(_user_id),
stat_follow_olh(_stat_follow_olh),
source_trace_entry(source_trace_entry),
counters(counters),
- dpp(dpp)
+ dpp(dpp),
+ keep_tags(_keep_tags)
{
if (_zones_trace) {
zones_trace = *_zones_trace;
rgw_zone_set *zones_trace;
PerfCounters* counters;
const DoutPrefixProvider *dpp;
+ bool keep_tags;
public:
RGWFetchRemoteObjCR(RGWAsyncRadosProcessor *_async_rados, rgw::sal::RadosStore* _store,
const rgw_zone_set_entry& source_trace_entry,
rgw_zone_set *_zones_trace,
PerfCounters* counters,
- const DoutPrefixProvider *dpp)
+ const DoutPrefixProvider *dpp,
+ bool _keep_tags)
: RGWSimpleCoroutine(_store->ctx()), cct(_store->ctx()),
async_rados(_async_rados), store(_store),
source_zone(_source_zone),
req(NULL),
stat_follow_olh(_stat_follow_olh),
source_trace_entry(source_trace_entry),
- zones_trace(_zones_trace), counters(counters), dpp(dpp) {}
+ zones_trace(_zones_trace), counters(counters), dpp(dpp), keep_tags(_keep_tags) {}
~RGWFetchRemoteObjCR() override {
req = new RGWAsyncFetchRemoteObj(this, stack->create_completion_notifier(), store,
source_zone, user_id, src_bucket, dest_placement_rule, dest_bucket_info,
key, dest_key, versioned_epoch, copy_if_newer, filter,
- stat_follow_olh, source_trace_entry, zones_trace, counters, dpp);
+ stat_follow_olh, source_trace_entry, zones_trace, counters, dpp, keep_tags);
async_rados->queue(req);
return 0;
}
{}, op);
}
+rgw::IAM::Effect RGWUserPermHandler::Bucket::evaluate_iam_policies(const rgw_obj_key& obj_key, const uint64_t op)
+{
+ const rgw_obj obj(ps->bucket_info.bucket, obj_key);
+ const auto arn = rgw::ARN(obj);
+ const bool account_root = (ps->identity->get_identity_type() == TYPE_ROOT);
+
+ return ::evaluate_iam_policies(dpp,
+ ps->env,
+ *ps->identity,
+ account_root,
+ op, arn,
+ bucket_policy,
+ info->user_policies,
+ {});
+}
+
int RGWUserPermHandler::policy_from_attrs(CephContext *cct,
const map<string, bufferlist>& attrs,
RGWAccessControlPolicy *acl) {
int try_num{0};
std::shared_ptr<bool> need_retry;
+ bool replicate_tags{true};
public:
RGWObjFetchCR(RGWDataSyncCtx *_sc,
rgw_bucket_sync_pipe& _sync_pipe,
}
user_perms.emplace(sync_env, *param_user);
- yield call(user_perms->init_cr());
+ yield call(user_perms->init_cr(sync_env));
if (retcode < 0) {
ldout(cct, 0) << "ERROR: " << __func__ << ": failed to init user perms manager for uid=" << *param_user << dendl;
return set_cr_error(retcode);
ldout(cct, 0) << "ERROR: " << __func__ << ": permission check failed: user not allowed to write into bucket (bucket=" << sync_pipe.info.dest_bucket.get_key() << ")" << dendl;
return set_cr_error(-EPERM);
}
+
+ // only if there is an explicit deny, we should not replicate tags
+ // otherwise, s3:ReplicateObject checked above already includes the permission to replicate tags
+ replicate_tags = dest_bucket_perms.evaluate_iam_policies(dest_key.value_or(key), rgw::IAM::s3ReplicateTags) != rgw::IAM::Effect::Deny;
+ ldout(cct, 20) << "replicate_tags=" << replicate_tags << dendl;
}
yield {
std::static_pointer_cast<RGWFetchObjFilter>(filter),
stat_follow_olh,
source_trace_entry, zones_trace,
- sync_env->counters, dpp));
+ sync_env->counters, dpp, replicate_tags));
}
if (retcode < 0) {
if (*need_retry) {
const std::map<std::string, bufferlist>& bucket_attrs);
bool verify_bucket_permission(const rgw_obj_key& obj_key, const uint64_t op);
+ rgw::IAM::Effect evaluate_iam_policies(const rgw_obj_key& obj_key, const uint64_t op);
};
static int policy_from_attrs(CephContext *cct,
const rgw_obj& stat_dest_obj,
std::optional<rgw_zone_set_entry> source_trace_entry,
rgw_zone_set *zones_trace,
- std::optional<uint64_t>* bytes_transferred)
+ std::optional<uint64_t>* bytes_transferred,
+ bool keep_tags)
{
/* source is in a different zonegroup, copy from there */
attrs = cb.get_attrs();
}
+ if (!keep_tags) {
+ attrs.erase(RGW_ATTR_TAGS);
+ }
+
if (copy_if_newer) {
uint64_t pg_ver = 0;
auto i = attrs.find(RGW_ATTR_PG_VER);
const rgw_obj& stat_dest_obj,
std::optional<rgw_zone_set_entry> source_trace_entry,
rgw_zone_set *zones_trace = nullptr,
- std::optional<uint64_t>* bytes_transferred = 0);
+ std::optional<uint64_t>* bytes_transferred = 0,
+ bool keep_tags = true);
/**
* Copy an object.
* dest_obj: the object to copy into
{ "s3:DescribeJob", s3DescribeJob },
{ "s3:ReplicateDelete", s3ReplicateDelete },
{ "s3:ReplicateObject", s3ReplicateObject },
+ { "s3:ReplicateTags", s3ReplicateTags },
{ "s3-object-lambda:GetObject", s3objectlambdaGetObject },
{ "s3-object-lambda:ListBucket", s3objectlambdaListBucket },
{ "iam:PutUserPolicy", iamPutUserPolicy },
case s3ReplicateObject:
return "s3:ReplicateObject";
+ case s3ReplicateTags:
+ return "s3:ReplicateTags";
+
case s3objectlambdaGetObject:
return "s3-object-lambda:GetObject";
s3GetObjectVersionAttributes,
s3ReplicateDelete,
s3ReplicateObject,
+ s3ReplicateTags,
s3All,
s3objectlambdaGetObject,
case s3BypassGovernanceRetention:
case s3ReplicateDelete:
case s3ReplicateObject:
+ case s3ReplicateTags:
return RGW_PERM_WRITE;
case s3GetAccelerateConfiguration: