fix: allow root to bypass bucket policy deny for policy management APIs

Per AWS S3 semantics, the account root can always perform
GetBucketPolicy, PutBucketPolicy, and DeleteBucketPolicy even when
the bucket policy explicitly denies. This enables recovery from
misconfigured Deny * policies (e.g. Console Private preset).

Also clear policy_config when policy_config_json is empty in
parse_all_configs to keep cache consistent after policy deletion.

Closes #2092

Made-with: Cursor
This commit is contained in:
GatewayJ
2026-03-08 14:02:40 +08:00
parent b035d10abb
commit a29b3fd08d
2 changed files with 13 additions and 0 deletions

View File

@@ -375,6 +375,8 @@ impl BucketMetadata {
fn parse_all_configs(&mut self, _api: Arc<ECStore>) -> Result<()> {
if !self.policy_config_json.is_empty() {
self.policy_config = Some(serde_json::from_slice(&self.policy_config_json)?);
} else {
self.policy_config = None;
}
if !self.notification_config_xml.is_empty() {
self.notification_config = Some(deserialize::<NotificationConfiguration>(&self.notification_config_xml)?);

View File

@@ -129,7 +129,18 @@ pub async fn authorize_request<T>(req: &mut S3Request<T>, action: Action) -> S3R
}
let bucket_name = req_info.bucket.as_deref().unwrap_or("");
// Per AWS S3: root can always perform GetBucketPolicy, PutBucketPolicy, DeleteBucketPolicy
// even if bucket policy explicitly denies. Other actions (ListBucket, GetObject, etc.) are
// subject to bucket policy Deny for root as well. See: repost.aws/knowledge-center/s3-accidentally-denied-access
let owner_can_bypass_deny = req_info.is_owner
&& matches!(
action,
Action::S3Action(S3Action::GetBucketPolicyAction)
| Action::S3Action(S3Action::PutBucketPolicyAction)
| Action::S3Action(S3Action::DeleteBucketPolicyAction)
);
if !bucket_name.is_empty()
&& !owner_can_bypass_deny
&& !PolicySys::is_allowed(&BucketPolicyArgs {
bucket: bucket_name,
action,