Skip to content

Commit 8be7d01

Browse files
authored
Merge pull request ceph#63043 from cbodley/wip-71115-tentacle
tentacle: rgw/sts: correcting authentication in case s3 ops are directed to a primary from secondary after assumerole. Reviewed-by: Seena Fallah <[email protected]>
2 parents 3feb86b + a5cb8a4 commit 8be7d01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1774
-350
lines changed

PendingReleaseNotes

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@
138138
allowed. `rbd trash mv` command now behaves the same way as `rbd rm` in this
139139
scenario.
140140

141+
* RGW: Replication policies now validate permissions using `s3:ReplicateObject`,
142+
`s3:ReplicateDelete`, and `s3:ReplicateTags` for destination buckets. For source
143+
buckets, both `s3:GetObjectVersionForReplication` and `s3:GetObject(Version)`
144+
are supported. Actions like `s3:GetObjectAcl`, `s3:GetObjectLegalHold`, and
145+
`s3:GetObjectRetention` are also considered when fetching the source object.
146+
Replication of tags is controlled by the `s3:GetObject(Version)Tagging` permission.
147+
141148
>=19.2.1
142149

143150
* CephFS: Command `fs subvolume create` now allows tagging subvolumes through option

qa/suites/rgw/multisite/overrides.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ overrides:
2020
rgw sync obj etag verify: true
2121
rgw sync meta inject err probability: 0
2222
rgw sync data inject err probability: 0
23+
rgw s3 auth use sts: true
24+
rgw sts key: abcdefghijklmnoq
2325
rgw:
2426
compression type: random

src/rgw/driver/rados/rgw_bucket_sync.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,31 @@ class RGWBucketSyncPolicyHandler {
415415
}
416416
};
417417

418+
struct rgw_bucket_sync_pair_info {
419+
RGWBucketSyncFlowManager::pipe_handler handler; /* responsible for sync filters */
420+
rgw_bucket_shard source_bs;
421+
rgw_bucket dest_bucket;
422+
};
423+
424+
inline std::ostream& operator<<(std::ostream& out, const rgw_bucket_sync_pair_info& p) {
425+
if (p.source_bs.bucket == p.dest_bucket) {
426+
return out << p.source_bs;
427+
}
428+
return out << p.source_bs << "->" << p.dest_bucket;
429+
}
430+
431+
struct rgw_bucket_sync_pipe {
432+
rgw_bucket_sync_pair_info info;
433+
RGWBucketInfo source_bucket_info;
434+
std::map<std::string, bufferlist> source_bucket_attrs;
435+
RGWBucketInfo dest_bucket_info;
436+
std::map<std::string, bufferlist> dest_bucket_attrs;
437+
438+
RGWBucketSyncFlowManager::pipe_rules_ref& get_rules() {
439+
return info.handler.rules;
440+
}
441+
};
442+
443+
inline std::ostream& operator<<(std::ostream& out, const rgw_bucket_sync_pipe& p) {
444+
return out << p.info;
445+
}

src/rgw/driver/rados/rgw_cr_rados.cc

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "rgw_cr_rest.h"
1313
#include "rgw_rest_conn.h"
1414
#include "rgw_rados.h"
15+
#include "rgw_data_sync.h"
1516

1617
#include "services/svc_zone.h"
1718
#include "services/svc_zone_utils.h"
@@ -812,7 +813,8 @@ int RGWAsyncFetchRemoteObj::_send_request(const DoutPrefixProvider *dpp)
812813
std::optional<uint64_t> bytes_transferred;
813814
const req_context rctx{dpp, null_yield, nullptr};
814815
int r = store->getRados()->fetch_remote_obj(obj_ctx,
815-
user_id.value_or(rgw_user()),
816+
NULL, /* uid */
817+
user_id ? &*user_id : nullptr, /* replication uid */
816818
NULL, /* req_info */
817819
source_zone,
818820
dest_obj.get_obj(),
@@ -843,7 +845,8 @@ int RGWAsyncFetchRemoteObj::_send_request(const DoutPrefixProvider *dpp)
843845
stat_dest_obj,
844846
source_trace_entry,
845847
&zones_trace,
846-
&bytes_transferred);
848+
&bytes_transferred,
849+
keep_tags);
847850

848851
if (r < 0) {
849852
ldpp_dout(dpp, 0) << "store->fetch_remote_obj() returned r=" << r << dendl;
@@ -873,7 +876,6 @@ int RGWAsyncStatRemoteObj::_send_request(const DoutPrefixProvider *dpp)
873876
{
874877
RGWObjectCtx obj_ctx(store);
875878

876-
string user_id;
877879
char buf[16];
878880
snprintf(buf, sizeof(buf), ".%lld", (long long)store->getRados()->instance_id());
879881

@@ -882,7 +884,7 @@ int RGWAsyncStatRemoteObj::_send_request(const DoutPrefixProvider *dpp)
882884

883885
int r = store->getRados()->stat_remote_obj(dpp,
884886
obj_ctx,
885-
rgw_user(user_id),
887+
nullptr, /* user_id */
886888
nullptr, /* req_info */
887889
source_zone,
888890
src_obj,
@@ -925,9 +927,55 @@ int RGWAsyncRemoveObj::_send_request(const DoutPrefixProvider *dpp)
925927
return 0;
926928
}
927929

928-
RGWAccessControlPolicy policy;
930+
RGWObjTags obj_tags;
931+
bufferlist bl_tag;
932+
if (obj->get_attr(RGW_ATTR_TAGS, bl_tag)) {
933+
auto bliter = bl_tag.cbegin();
934+
try {
935+
obj_tags.decode(bliter);
936+
} catch (buffer::error &err) {
937+
ldpp_dout(dpp, 0) << "ERROR: " << __func__ << ": caught buffer::error couldn't decode TagSet " << dendl;
938+
return -EIO;
939+
}
940+
}
941+
942+
rgw_sync_pipe_params params;
943+
if (!sync_pipe.info.handler.find_obj_params(obj->get_key(),
944+
obj_tags.get_tags(),
945+
&params)) {
946+
return -ERR_PRECONDITION_FAILED;
947+
}
948+
949+
if (params.mode == rgw_sync_pipe_params::MODE_USER) {
950+
std::optional<RGWUserPermHandler> user_perms;
951+
RGWUserPermHandler::Bucket dest_bucket_perms;
952+
953+
if (!params.user.has_value()) {
954+
ldpp_dout(dpp, 20) << "ERROR: " << __func__ << ": user level sync but user param not set" << dendl;
955+
return -EPERM;
956+
}
957+
user_perms.emplace(dpp, store, dpp->get_cct(), *params.user);
958+
959+
ret = user_perms->init();
960+
if (ret < 0) {
961+
ldpp_dout(dpp, 0) << "ERROR: " << __func__ << ": failed to init user perms for uid=" << *params.user << " ret=" << ret << dendl;
962+
return ret;
963+
}
964+
965+
ret = user_perms->init_bucket(sync_pipe.dest_bucket_info, sync_pipe.dest_bucket_attrs, &dest_bucket_perms);
966+
if (ret < 0) {
967+
ldpp_dout(dpp, 0) << "ERROR: " << __func__ << ": failed to init bucket perms for uid=" << *params.user << " bucket=" << bucket->get_key() << " ret=" << ret << dendl;
968+
return ret;
969+
}
970+
971+
if (!dest_bucket_perms.verify_bucket_permission(obj->get_key(), rgw::IAM::s3ReplicateDelete)) {
972+
ldpp_dout(dpp, 20) << "ERROR: " << __func__ << ": user does not have permission to delete object" << dendl;
973+
return -EPERM;
974+
}
975+
}
929976

930977
/* decode policy */
978+
RGWAccessControlPolicy policy;
931979
bufferlist bl;
932980
if (obj->get_attr(RGW_ATTR_ACL, bl)) {
933981
auto bliter = bl.cbegin();

src/rgw/driver/rados/rgw_cr_rados.h

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "rgw_coroutine.h"
99
#include "rgw_sal.h"
1010
#include "rgw_sal_rados.h"
11+
#include "rgw_bucket_sync.h"
1112
#include "common/WorkQueue.h"
1213
#include "common/Throttle.h"
1314

@@ -1129,6 +1130,7 @@ class RGWAsyncFetchRemoteObj : public RGWAsyncRadosRequest {
11291130
rgw_zone_set zones_trace;
11301131
PerfCounters* counters;
11311132
const DoutPrefixProvider *dpp;
1133+
bool keep_tags;
11321134

11331135
protected:
11341136
int _send_request(const DoutPrefixProvider *dpp) override;
@@ -1148,7 +1150,8 @@ class RGWAsyncFetchRemoteObj : public RGWAsyncRadosRequest {
11481150
const rgw_zone_set_entry& source_trace_entry,
11491151
rgw_zone_set *_zones_trace,
11501152
PerfCounters* counters,
1151-
const DoutPrefixProvider *dpp)
1153+
const DoutPrefixProvider *dpp,
1154+
bool _keep_tags)
11521155
: RGWAsyncRadosRequest(caller, cn), store(_store),
11531156
source_zone(_source_zone),
11541157
user_id(_user_id),
@@ -1163,7 +1166,8 @@ class RGWAsyncFetchRemoteObj : public RGWAsyncRadosRequest {
11631166
stat_follow_olh(_stat_follow_olh),
11641167
source_trace_entry(source_trace_entry),
11651168
counters(counters),
1166-
dpp(dpp)
1169+
dpp(dpp),
1170+
keep_tags(_keep_tags)
11671171
{
11681172
if (_zones_trace) {
11691173
zones_trace = *_zones_trace;
@@ -1199,6 +1203,7 @@ class RGWFetchRemoteObjCR : public RGWSimpleCoroutine {
11991203
rgw_zone_set *zones_trace;
12001204
PerfCounters* counters;
12011205
const DoutPrefixProvider *dpp;
1206+
bool keep_tags;
12021207

12031208
public:
12041209
RGWFetchRemoteObjCR(RGWAsyncRadosProcessor *_async_rados, rgw::sal::RadosStore* _store,
@@ -1216,7 +1221,8 @@ class RGWFetchRemoteObjCR : public RGWSimpleCoroutine {
12161221
const rgw_zone_set_entry& source_trace_entry,
12171222
rgw_zone_set *_zones_trace,
12181223
PerfCounters* counters,
1219-
const DoutPrefixProvider *dpp)
1224+
const DoutPrefixProvider *dpp,
1225+
bool _keep_tags)
12201226
: RGWSimpleCoroutine(_store->ctx()), cct(_store->ctx()),
12211227
async_rados(_async_rados), store(_store),
12221228
source_zone(_source_zone),
@@ -1232,7 +1238,7 @@ class RGWFetchRemoteObjCR : public RGWSimpleCoroutine {
12321238
req(NULL),
12331239
stat_follow_olh(_stat_follow_olh),
12341240
source_trace_entry(source_trace_entry),
1235-
zones_trace(_zones_trace), counters(counters), dpp(dpp) {}
1241+
zones_trace(_zones_trace), counters(counters), dpp(dpp), keep_tags(_keep_tags) {}
12361242

12371243

12381244
~RGWFetchRemoteObjCR() override {
@@ -1250,7 +1256,7 @@ class RGWFetchRemoteObjCR : public RGWSimpleCoroutine {
12501256
req = new RGWAsyncFetchRemoteObj(this, stack->create_completion_notifier(), store,
12511257
source_zone, user_id, src_bucket, dest_placement_rule, dest_bucket_info,
12521258
key, dest_key, versioned_epoch, copy_if_newer, filter,
1253-
stat_follow_olh, source_trace_entry, zones_trace, counters, dpp);
1259+
stat_follow_olh, source_trace_entry, zones_trace, counters, dpp, keep_tags);
12541260
async_rados->queue(req);
12551261
return 0;
12561262
}
@@ -1360,7 +1366,9 @@ class RGWStatRemoteObjCR : public RGWSimpleCoroutine {
13601366
class RGWAsyncRemoveObj : public RGWAsyncRadosRequest {
13611367
const DoutPrefixProvider *dpp;
13621368
rgw::sal::RadosStore* store;
1369+
CephContext *cct;
13631370
rgw_zone_id source_zone;
1371+
rgw_bucket_sync_pipe& sync_pipe;
13641372

13651373
std::unique_ptr<rgw::sal::Bucket> bucket;
13661374
std::unique_ptr<rgw::sal::Object> obj;
@@ -1379,33 +1387,35 @@ class RGWAsyncRemoveObj : public RGWAsyncRadosRequest {
13791387
int _send_request(const DoutPrefixProvider *dpp) override;
13801388
public:
13811389
RGWAsyncRemoveObj(const DoutPrefixProvider *_dpp, RGWCoroutine *caller, RGWAioCompletionNotifier *cn,
1382-
rgw::sal::RadosStore* _store,
1383-
const rgw_zone_id& _source_zone,
1384-
RGWBucketInfo& _bucket_info,
1385-
const rgw_obj_key& _key,
1386-
const std::string& _owner,
1387-
const std::string& _owner_display_name,
1388-
bool _versioned,
1389-
uint64_t _versioned_epoch,
1390-
bool _delete_marker,
1391-
bool _if_older,
1392-
real_time& _timestamp,
1393-
rgw_zone_set* _zones_trace) : RGWAsyncRadosRequest(caller, cn), dpp(_dpp), store(_store),
1394-
source_zone(_source_zone),
1395-
owner(_owner),
1396-
owner_display_name(_owner_display_name),
1397-
versioned(_versioned),
1398-
versioned_epoch(_versioned_epoch),
1399-
del_if_older(_if_older),
1400-
timestamp(_timestamp) {
1390+
rgw::sal::RadosStore* _store,
1391+
CephContext *_cct,
1392+
const rgw_zone_id& _source_zone,
1393+
rgw_bucket_sync_pipe& _sync_pipe,
1394+
const rgw_obj_key& _key,
1395+
const std::string& _owner,
1396+
const std::string& _owner_display_name,
1397+
bool _versioned,
1398+
uint64_t _versioned_epoch,
1399+
bool _delete_marker,
1400+
bool _if_older,
1401+
real_time& _timestamp,
1402+
rgw_zone_set* _zones_trace) : RGWAsyncRadosRequest(caller, cn), dpp(_dpp), store(_store), cct(_cct),
1403+
source_zone(_source_zone),
1404+
sync_pipe(_sync_pipe),
1405+
owner(_owner),
1406+
owner_display_name(_owner_display_name),
1407+
versioned(_versioned),
1408+
versioned_epoch(_versioned_epoch),
1409+
del_if_older(_if_older),
1410+
timestamp(_timestamp) {
14011411
if (_delete_marker) {
14021412
marker_version_id = _key.instance;
14031413
}
14041414

14051415
if (_zones_trace) {
14061416
zones_trace = *_zones_trace;
14071417
}
1408-
bucket = store->get_bucket(_bucket_info);
1418+
bucket = store->get_bucket(sync_pipe.dest_bucket_info);
14091419
obj = bucket->get_object(_key);
14101420
}
14111421
};
@@ -1417,7 +1427,7 @@ class RGWRemoveObjCR : public RGWSimpleCoroutine {
14171427
rgw::sal::RadosStore* store;
14181428
rgw_zone_id source_zone;
14191429

1420-
RGWBucketInfo bucket_info;
1430+
rgw_bucket_sync_pipe& sync_pipe;
14211431

14221432
rgw_obj_key key;
14231433
bool versioned;
@@ -1436,7 +1446,7 @@ class RGWRemoveObjCR : public RGWSimpleCoroutine {
14361446
public:
14371447
RGWRemoveObjCR(const DoutPrefixProvider *_dpp, RGWAsyncRadosProcessor *_async_rados, rgw::sal::RadosStore* _store,
14381448
const rgw_zone_id& _source_zone,
1439-
RGWBucketInfo& _bucket_info,
1449+
rgw_bucket_sync_pipe& _sync_pipe,
14401450
const rgw_obj_key& _key,
14411451
bool _versioned,
14421452
uint64_t _versioned_epoch,
@@ -1447,7 +1457,7 @@ class RGWRemoveObjCR : public RGWSimpleCoroutine {
14471457
rgw_zone_set *_zones_trace) : RGWSimpleCoroutine(_store->ctx()), dpp(_dpp), cct(_store->ctx()),
14481458
async_rados(_async_rados), store(_store),
14491459
source_zone(_source_zone),
1450-
bucket_info(_bucket_info),
1460+
sync_pipe(_sync_pipe),
14511461
key(_key),
14521462
versioned(_versioned),
14531463
versioned_epoch(_versioned_epoch),
@@ -1477,7 +1487,7 @@ class RGWRemoveObjCR : public RGWSimpleCoroutine {
14771487
}
14781488

14791489
int send_request(const DoutPrefixProvider *dpp) override {
1480-
req = new RGWAsyncRemoveObj(dpp, this, stack->create_completion_notifier(), store, source_zone, bucket_info,
1490+
req = new RGWAsyncRemoveObj(dpp, this, stack->create_completion_notifier(), store, cct, source_zone, sync_pipe,
14811491
key, owner, owner_display_name, versioned, versioned_epoch,
14821492
delete_marker, del_if_older, timestamp, zones_trace);
14831493
async_rados->queue(req);

0 commit comments

Comments
 (0)