Bucket Policies are defined in IAM JSON policy schema format rules which define the actions that can be performed on a bucket under defined conditions. You may want to use them to limit the scope of access to the bucket or control which operations can be performed by users of your application.
Since Onidel Object Storage is based on CEPH, it has support for Bucket Policies following the CEPH Object Gateway implementation.
This tutorial is to showcase how to set up and verify bucket policies. To follow along, you will need to have a bucket created and s3cmd utility set up to access it. We will use the s3cmd utility to manage active bucket policy, however you may use a different tool, or even create one yourself.
Creating a Bucket Policy
To define a policy, you first need to create a local policy.json file. Below is an example of how it might look like.
{
"Version": "2012-10-17",
"Statement":[
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": "*",
"Action":[
"s3:GetObject",
"s3:ListBucket"
],
"Resource":[
"arn:aws:s3:::cat-pictures",
"arn:aws:s3:::cat-pictures/*"
]
},
{
"Sid": "DenyWriteAndDelete",
"Effect": "Deny",
"Principal": "*",
"Action":[
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::cat-pictures/*"
}
]
}
This policy assumes your bucket is named cat-pictures. It will make the objects Read Only by disallowing PutObject and DeleteObject actions. GetObject and ListBucket are operations that do not modify the contents of bucket, and the policy explicitly allows those.
Checking Active Bucket Policy
To see what policy is already defined on your bucket, you may use the s3cmd info command.
$ s3cmd info s3://cat-pictures
s3://cat-pictures/ (bucket):
Location: ap-southeast-1
Payer: BucketOwner
Ownership: none
Versioning:none
Expiration rule: none
Block Public Access: none
Policy: none
CORS: none
ACL: 54132dec-5121-4932-8f91-3c2cc2cbea28: FULL_CONTROL
Currently no policy is applied to the bucket (Policy: none).
Applying Policy
To apply the policy we defined a few steps above, navigate to the same folder your policy file is in and execute the s3cmd setpolicy command.
$ s3cmd setpolicy policy.json s3://cat-pictures
s3://cat-pictures/: Policy updated
As you can see, the policy got applied successfully.
$ s3cmd info s3://cat-pictures
s3://cat-pictures/ (bucket):
Location: ap-southeast-1
Payer: BucketOwner
Ownership: none
Versioning:none
Expiration rule: none
Block Public Access: none
Policy: {
"Version": "2012-10-17",
"Statement":[
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": "*",
"Action":[
"s3:GetObject",
"s3:ListBucket"
],
"Resource":[
"arn:aws:s3:::cat-pictures",
"arn:aws:s3:::cat-pictures/*"
]
},
{
"Sid": "DenyWriteAndDelete",
"Effect": "Deny",
"Principal": "*",
"Action":[
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::cat-pictures/*"
}
]
}
CORS: none
ACL: 54132dec-5121-4932-8f91-3c2cc2cbea28: FULL_CONTROL
Verification
Now, let's see if the policy we defined works in practice. We will try to upload a new object as well as deleting the existing one:
$ s3cmd ls s3://cat-pictures
2026-03-14 15:05 20425 s3://cat-pictures/cat1.jpg
2026-03-14 15:05 57982 s3://cat-pictures/cat2.jpg
2026-03-14 15:05 68630 s3://cat-pictures/cat3.webp
2026-03-14 15:05 32602 s3://cat-pictures/cat4.jpg
2026-03-14 15:05 67608 s3://cat-pictures/cat5.jpg
$ s3cmd put cat6.jpg s3://cat-pictures
upload: 'cat6.jpg' -> 's3://cat-pictures/cat6.jpg' [1 of 1]
38403 of 38403 100% in 0s 39.31 KB/s done
ERROR: S3 error: 403 (AccessDenied)
$ s3cmd del s3://cat-pictures/cat5.jpg
ERROR: S3 error: 403 (AccessDenied)
We got AccessDenied error in both cases, which is expected. However the listing of objects was successful. You can also read an object with s3cmd get, as allowed by policy.
$ s3cmd get s3://cat-pictures/cat5.jpg
download: 's3://cat-pictures/cat5.jpg' -> './cat5.jpg' [1 of 1]
67608 of 67608 100% in 0s 114.29 KB/s done
Removing Policy
You may delete existing policy by issuing the s3cmd delpolicy command.
$ s3cmd delpolicy s3://cat-pictures
s3://cat-pictures/: Policy deleted
$ s3cmd info s3://cat-pictures
s3://cat-pictures/ (bucket):
Location: ap-southeast-1
Payer: BucketOwner
Ownership: none
Versioning:none
Expiration rule: none
Block Public Access: none
Policy: none
CORS: none
ACL: 54132dec-5121-4932-8f91-3c2cc2cbea28: FULL_CONTROL
Now the policy should not apply anymore, we are able to upload a new object to the bucket and delete existing one.
$ s3cmd put cat6.jpg s3://cat-pictures
upload: 'cat6.jpg' -> 's3://cat-pictures/cat6.jpg' [1 of 1]
38403 of 38403 100% in 1s 37.41 KB/s done
$ s3cmd del s3://cat-pictures/cat5.jpg
delete: 's3://cat-pictures/cat5.jpg'
$ s3cmd ls s3://cat-pictures
2026-03-14 15:05 20425 s3://cat-pictures/cat1.jpg
2026-03-14 15:05 57982 s3://cat-pictures/cat2.jpg
2026-03-14 15:05 68630 s3://cat-pictures/cat3.webp
2026-03-14 15:05 32602 s3://cat-pictures/cat4.jpg
2026-03-14 23:12 38403 s3://cat-pictures/cat6.jpg
Additional Notes
Do note that CEPH implementation of Bucket Policies is still somewhat limited, you may find that some of your existing policies will not work with Onidel Cloud Object Storage.
If you plan to implement more sophisticated policies, you may want to look at policy examples from the AWS docs.