diff --git a/crates/ecstore/src/bucket/metadata.rs b/crates/ecstore/src/bucket/metadata.rs index 67230099..3451d34f 100644 --- a/crates/ecstore/src/bucket/metadata.rs +++ b/crates/ecstore/src/bucket/metadata.rs @@ -375,6 +375,8 @@ impl BucketMetadata { fn parse_all_configs(&mut self, _api: Arc) -> 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::(&self.notification_config_xml)?); diff --git a/rustfs/src/storage/access.rs b/rustfs/src/storage/access.rs index 41e14653..38cec9bd 100644 --- a/rustfs/src/storage/access.rs +++ b/rustfs/src/storage/access.rs @@ -129,7 +129,18 @@ pub async fn authorize_request(req: &mut S3Request, 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,