Skip to content

Commit 7e47dee

Browse files
committed
rgw: reject PutBucketReplication on mismatched versioning and lock
Reject PutBucketReplication calls if versioning is not identical between the source and destination buckets. This check also applies to object lock configurations to ensure consistency. Fixes: https://tracker.ceph.com/issues/70486 Signed-off-by: Seena Fallah <[email protected]>
1 parent 320a4e6 commit 7e47dee

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

src/rgw/rgw_rest_s3.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,28 @@ struct ReplicationConfiguration {
13391339
}
13401340
pipe->dest.bucket.emplace(dest_bk);
13411341

1342+
std::unique_ptr<rgw::sal::Bucket> dest_bucket;
1343+
if (int r = driver->load_bucket(s, *pipe->dest.bucket, &dest_bucket, s->yield); r < 0) {
1344+
if (r == -ENOENT) {
1345+
s->err.message = "Destination bucket must exist.";
1346+
return -EINVAL;
1347+
}
1348+
1349+
ldpp_dout(s, 0) << "ERROR: failed to load bucket info for bucket=" << *pipe->dest.bucket << " r=" << r << dendl;
1350+
return r;
1351+
}
1352+
1353+
// check versioning identicality
1354+
if (dest_bucket->get_info().versioned() != s->bucket->get_info().versioned()) {
1355+
s->err.message = "Versioning must be identical in source and destination buckets.";
1356+
return -EINVAL;
1357+
}
1358+
// check object lock identicality
1359+
if (dest_bucket->get_info().obj_lock_enabled() != s->bucket->get_info().obj_lock_enabled()) {
1360+
s->err.message = "Object lock must be identical in source and destination buckets.";
1361+
return -EINVAL;
1362+
}
1363+
13421364
if (filter) {
13431365
int r = filter->to_sync_pipe_filter(s->cct, &pipe->params.source.filter);
13441366
if (r < 0) {

src/test/rgw/rgw_multi/tests.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3885,3 +3885,64 @@ def test_bucket_replication_alt_user():
38853885
# check that object exists in destination bucket
38863886
k = get_key(dest, dest_bucket, objname)
38873887
assert_equal(k.get_contents_as_string().decode('utf-8'), 'foo')
3888+
3889+
@allow_bucket_replication
3890+
def test_bucket_replication_reject_versioning_identical():
3891+
zonegroup = realm.master_zonegroup()
3892+
zonegroup_conns = ZonegroupConns(zonegroup)
3893+
3894+
source = zonegroup_conns.non_account_rw_zones[0]
3895+
dest = zonegroup_conns.non_account_rw_zones[1]
3896+
3897+
source_bucket = source.create_bucket(gen_bucket_name())
3898+
dest_bucket = dest.create_bucket(gen_bucket_name())
3899+
source.s3_client.put_bucket_versioning(
3900+
Bucket=source_bucket.name,
3901+
VersioningConfiguration={'Status': 'Enabled'}
3902+
)
3903+
zonegroup_meta_checkpoint(zonegroup)
3904+
3905+
# create replication configuration
3906+
e = assert_raises(ClientError,
3907+
source.s3_client.put_bucket_replication,
3908+
Bucket=source_bucket.name,
3909+
ReplicationConfiguration={
3910+
'Role': '',
3911+
'Rules': [{
3912+
'ID': 'rule1',
3913+
'Status': 'Enabled',
3914+
'Destination': {
3915+
'Bucket': f'arn:aws:s3:::{dest_bucket.name}',
3916+
}
3917+
}]
3918+
})
3919+
assert e.response['ResponseMetadata']['HTTPStatusCode'] == 400
3920+
3921+
@allow_bucket_replication
3922+
def test_bucket_replicaion_reject_objectlock_identical():
3923+
zonegroup = realm.master_zonegroup()
3924+
zonegroup_conns = ZonegroupConns(zonegroup)
3925+
3926+
source = zonegroup_conns.non_account_rw_zones[0]
3927+
dest = zonegroup_conns.non_account_rw_zones[1]
3928+
3929+
source_bucket = source.create_bucket(gen_bucket_name())
3930+
dest_bucket_name = gen_bucket_name()
3931+
dest.s3_client.create_bucket(Bucket=dest_bucket_name, ObjectLockEnabledForBucket=True)
3932+
zonegroup_meta_checkpoint(zonegroup)
3933+
3934+
# create replication configuration
3935+
e = assert_raises(ClientError,
3936+
source.s3_client.put_bucket_replication,
3937+
Bucket=source_bucket.name,
3938+
ReplicationConfiguration={
3939+
'Role': '',
3940+
'Rules': [{
3941+
'ID': 'rule1',
3942+
'Status': 'Enabled',
3943+
'Destination': {
3944+
'Bucket': f'arn:aws:s3:::{dest_bucket_name}',
3945+
}
3946+
}]
3947+
})
3948+
assert e.response['ResponseMetadata']['HTTPStatusCode'] == 400

0 commit comments

Comments
 (0)