Skip to content

Commit b1cdf2f

Browse files
authored
Merge pull request ceph#64152 from cbodley/wip-63323
rgw: support S3 Object Ownership controls to disable object ACLs Reviewed-by: Adam Emerson <[email protected]>
2 parents 2b14a67 + 92a371e commit b1cdf2f

21 files changed

+520
-15
lines changed

PendingReleaseNotes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
- osd_op_num_shards_hdd = 1 (was 5)
6464
- osd_op_num_threads_per_shard_hdd = 5 (was 1)
6565
For more details see https://tracker.ceph.com/issues/66289.
66+
* RGW: Added support for S3 Object Ownership to disable object ACLs.
6667
* MGR: The Ceph Manager's always-on modulues/plugins can now be force-disabled.
6768
This can be necessary when we wish to prevent the Manager from being
6869
flooded by module commands when Ceph services are down or degraded.

doc/radosgw/s3.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ The following table describes the support status for current Amazon S3 functiona
8484
+---------------------------------+-----------------+--------------------------------------------------+
8585
| **Bucket Logging** | Supported | |
8686
+---------------------------------+-----------------+--------------------------------------------------+
87+
| **Object Ownership** | Supported | |
88+
+---------------------------------+-----------------+--------------------------------------------------+
8789

8890
Unsupported Header Fields
8991
-------------------------

doc/radosgw/s3/bucketops.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ Parameters
4545
+--------------------------------------+-------------------------------+-----------------------------------------------+------------+
4646
| ``x-amz-bucket-object-lock-enabled`` | Enable object lock on bucket. | ``true``, ``false`` | No |
4747
+--------------------------------------+-------------------------------+-----------------------------------------------+------------+
48+
| ``x-amz-object-ownership`` | Set ownership controls. | ``BucketOwnerEnforced``, | No |
49+
| | | ``BucketOwnerPreferred``, ``ObjectWriter`` | |
50+
+--------------------------------------+-------------------------------+-----------------------------------------------+------------+
4851

4952
Request Entities
5053
~~~~~~~~~~~~~~~~

src/rgw/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ set(librgw_common_srcs
7272
rgw_multi_del.cc
7373
rgw_multipart_meta_filter.cc
7474
rgw_obj_manifest.cc
75+
rgw_object_ownership.cc
7576
rgw_period.cc
7677
rgw_realm.cc
7778
rgw_sync.cc

src/rgw/driver/rados/rgw_data_sync.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2693,6 +2693,7 @@ int RGWUserPermHandler::Bucket::init(RGWUserPermHandler *handler,
26932693
info->env,
26942694
info->identity.get(),
26952695
bucket_info,
2696+
rgw::s3::ObjectOwnership::ObjectWriter,
26962697
info->identity->get_perm_mask(),
26972698
false, /* defer to bucket acls */
26982699
nullptr, /* referer */

src/rgw/rgw_acl_s3.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,14 +677,32 @@ void write_policy_xml(const RGWAccessControlPolicy& policy,
677677

678678
int create_canned_acl(const ACLOwner& owner,
679679
const ACLOwner& bucket_owner,
680+
ObjectOwnership object_ownership,
680681
const std::string& canned_acl,
681-
RGWAccessControlPolicy& policy)
682+
RGWAccessControlPolicy& policy,
683+
std::string& error_message)
682684
{
683685
if (owner.id == parse_owner("anonymous")) {
684686
policy.set_owner(bucket_owner);
685687
} else {
686688
policy.set_owner(owner);
687689
}
690+
691+
// special handling for BucketOwnerEnforced/Preferred
692+
if (object_ownership == ObjectOwnership::BucketOwnerEnforced) {
693+
// only supports bucket-owner-full-control
694+
if (canned_acl != "" && canned_acl != "bucket-owner-full-control") {
695+
error_message = "Cannot set ACLs when ObjectOwnership is BucketOwnerEnforced.";
696+
return -ERR_ACLS_NOT_SUPPORTED;
697+
}
698+
policy.set_owner(bucket_owner);
699+
} else if (object_ownership == ObjectOwnership::BucketOwnerPreferred) {
700+
// prefer bucket owner only for bucket-owner-full-control
701+
if (canned_acl == "bucket-owner-full-control") {
702+
policy.set_owner(bucket_owner);
703+
}
704+
}
705+
688706
return create_canned(owner, bucket_owner, canned_acl, policy.get_acl());
689707
}
690708

src/rgw/rgw_acl_s3.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "common/async/yield_context.h"
1212
#include "rgw_xml.h"
1313
#include "rgw_acl.h"
14+
#include "rgw_object_ownership.h"
1415
#include "rgw_sal_fwd.h"
1516

1617
class RGWEnv;
@@ -34,8 +35,10 @@ void write_policy_xml(const RGWAccessControlPolicy& policy,
3435
/// Construct a policy from a s3 canned acl string.
3536
int create_canned_acl(const ACLOwner& owner,
3637
const ACLOwner& bucket_owner,
38+
ObjectOwnership object_ownership,
3739
const std::string& canned_acl,
38-
RGWAccessControlPolicy& policy);
40+
RGWAccessControlPolicy& policy,
41+
std::string& error_message);
3942

4043
/// Construct a policy from x-amz-grant-* request headers.
4144
int create_policy_from_headers(const DoutPrefixProvider* dpp,

src/rgw/rgw_bucket.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,14 @@ int rgw_chown_bucket_and_objects(rgw::sal::Driver* driver, rgw::sal::Bucket* buc
140140
int ret = bucket->chown(dpp, new_user->get_id(), new_user->get_display_name(),
141141
y);
142142
if (ret < 0) {
143-
set_err_msg(err_msg, "Failed to change object ownership: " + cpp_strerror(-ret));
143+
set_err_msg(err_msg, "Failed to change bucket ownership: " + cpp_strerror(-ret));
144+
return ret;
145+
}
146+
147+
// skip object acls when BucketOwnerEnforced
148+
if (auto ownership = rgw::s3::get_object_ownership(bucket->get_attrs());
149+
ownership == rgw::s3::ObjectOwnership::BucketOwnerEnforced) {
150+
return 0;
144151
}
145152

146153
/* Now chown on all the objects in the bucket */

src/rgw/rgw_common.cc

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ rgw_http_errors rgw_http_s3_errors({
145145
{ ECANCELED, {409, "ConcurrentModification"}},
146146
{ EDQUOT, {507, "InsufficientCapacity"}},
147147
{ ENOSPC, {507, "InsufficientCapacity"}},
148+
{ ERR_ACLS_NOT_SUPPORTED, {400, "AccessControlListNotSupported"}},
149+
{ ERR_INVALID_BUCKET_ACL, {400, "InvalidBucketAclWithObjectOwnership"}},
150+
{ ERR_NO_SUCH_OWNERSHIP_CONTROLS, {404, "OwnershipControlsNotFoundError"}},
148151
});
149152

150153
rgw_http_errors rgw_http_swift_errors({
@@ -1118,6 +1121,7 @@ struct perm_state_from_req_state : public perm_state_base {
11181121
_s->env,
11191122
_s->auth.identity.get(),
11201123
_s->bucket.get() ? _s->bucket->get_info() : RGWBucketInfo(),
1124+
_s->bucket_object_ownership,
11211125
_s->perm_mask,
11221126
_s->defer_to_bucket_acls,
11231127
_s->bucket_access_conf),
@@ -1625,11 +1629,12 @@ bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp,
16251629
return true;
16261630
}
16271631

1628-
bool ret = object_acl.verify_permission(dpp, *ps->identity, ps->perm_mask, perm,
1629-
nullptr, /* http referrer */
1630-
ps->bucket_access_conf &&
1631-
ps->bucket_access_conf->ignore_public_acls());
1632-
if (ret) {
1632+
// object ACLs don't apply for BucketOwnerEnforced
1633+
if (ps->bucket_object_ownership != rgw::s3::ObjectOwnership::BucketOwnerEnforced &&
1634+
object_acl.verify_permission(dpp, *ps->identity, ps->perm_mask, perm,
1635+
nullptr, /* http referrer */
1636+
ps->bucket_access_conf &&
1637+
ps->bucket_access_conf->ignore_public_acls())) {
16331638
ldpp_dout(dpp, 10) << __func__ << ": granted by object acl" << dendl;
16341639
if (granted_by_acl) {
16351640
*granted_by_acl = true;
@@ -1638,7 +1643,7 @@ bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp,
16381643
}
16391644

16401645
if (!ps->cct->_conf->rgw_enforce_swift_acls)
1641-
return ret;
1646+
return false;
16421647

16431648
if ((perm & (int)ps->perm_mask) != perm)
16441649
return false;

src/rgw/rgw_common.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "common/async/yield_context.h"
4444
#include "rgw_website.h"
4545
#include "rgw_object_lock.h"
46+
#include "rgw_object_ownership.h"
4647
#include "rgw_tag.h"
4748
#include "rgw_op_type.h"
4849
#include "rgw_sync_policy.h"
@@ -121,6 +122,8 @@ using ceph::crypto::MD5;
121122
#define RGW_ATTR_OBJECT_RETENTION RGW_ATTR_PREFIX "object-retention"
122123
#define RGW_ATTR_OBJECT_LEGAL_HOLD RGW_ATTR_PREFIX "object-legal-hold"
123124

125+
// S3 Object Ownership
126+
#define RGW_ATTR_OWNERSHIP_CONTROLS RGW_ATTR_PREFIX "ownership-controls"
124127

125128
#define RGW_ATTR_PG_VER RGW_ATTR_PREFIX "pg_ver"
126129
#define RGW_ATTR_SOURCE_ZONE RGW_ATTR_PREFIX "source_zone"
@@ -350,6 +353,9 @@ inline constexpr const char* RGW_REST_STS_XMLNS =
350353
#define ERR_PRESIGNED_URL_DISABLED 2224
351354
#define ERR_AUTHORIZATION 2225 // SNS 403 AuthorizationError
352355
#define ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION 2226
356+
#define ERR_ACLS_NOT_SUPPORTED 2227 // 400 AccessControlListNotSupported
357+
#define ERR_INVALID_BUCKET_ACL 2228 // 400 InvalidBucketAclWithObjectOwnership
358+
#define ERR_NO_SUCH_OWNERSHIP_CONTROLS 2229 // 404 OwnershipControlsNotFoundError
353359

354360
#define ERR_BUSY_RESHARDING 2300 // also in cls_rgw_types.h, don't change!
355361
#define ERR_NO_SUCH_ENTITY 2301
@@ -1382,6 +1388,7 @@ struct req_state : DoutPrefixProvider {
13821388
rgw::IAM::Environment env;
13831389
boost::optional<rgw::IAM::Policy> iam_policy;
13841390
boost::optional<PublicAccessBlockConfiguration> bucket_access_conf;
1391+
rgw::s3::ObjectOwnership bucket_object_ownership = rgw::s3::ObjectOwnership::ObjectWriter;
13851392
std::vector<rgw::IAM::Policy> iam_identity_policies;
13861393

13871394
/* Is the request made by an user marked as a system one?
@@ -1696,6 +1703,7 @@ struct perm_state_base {
16961703
const rgw::IAM::Environment& env;
16971704
rgw::auth::Identity *identity;
16981705
const RGWBucketInfo bucket_info;
1706+
rgw::s3::ObjectOwnership bucket_object_ownership;
16991707
int perm_mask;
17001708
bool defer_to_bucket_acls;
17011709
boost::optional<PublicAccessBlockConfiguration> bucket_access_conf;
@@ -1704,13 +1712,15 @@ struct perm_state_base {
17041712
const rgw::IAM::Environment& _env,
17051713
rgw::auth::Identity *_identity,
17061714
const RGWBucketInfo& _bucket_info,
1715+
rgw::s3::ObjectOwnership bucket_object_ownership,
17071716
int _perm_mask,
17081717
bool _defer_to_bucket_acls,
17091718
boost::optional<PublicAccessBlockConfiguration> _bucket_access_conf = boost::none) :
17101719
cct(_cct),
17111720
env(_env),
17121721
identity(_identity),
17131722
bucket_info(_bucket_info),
1723+
bucket_object_ownership(bucket_object_ownership),
17141724
perm_mask(_perm_mask),
17151725
defer_to_bucket_acls(_defer_to_bucket_acls),
17161726
bucket_access_conf(_bucket_access_conf)
@@ -1733,13 +1743,15 @@ struct perm_state : public perm_state_base {
17331743
const rgw::IAM::Environment& _env,
17341744
rgw::auth::Identity *_identity,
17351745
const RGWBucketInfo& _bucket_info,
1746+
rgw::s3::ObjectOwnership bucket_object_ownership,
17361747
int _perm_mask,
17371748
bool _defer_to_bucket_acls,
17381749
const char *_referer,
17391750
bool _request_payer) : perm_state_base(_cct,
17401751
_env,
17411752
_identity,
17421753
_bucket_info,
1754+
bucket_object_ownership,
17431755
_perm_mask,
17441756
_defer_to_bucket_acls),
17451757
referer(_referer),

0 commit comments

Comments
 (0)