PutBucketAcl
PutBucketAcl sets a bucket's access control list (ACL) - who may read the bucket's objects. On
STRG a bucket's ACL is always one of two canned ACLs, and it is the bucket's Bucket
Protection setting in the dashboard: private is Protected, public-read is Public. Setting
it through the API is handy wherever a script, a tool or an agent looks after a bucket, and
GetBucketAcl reads it back.
- A bucket's ACL is
privateorpublic-read, the two choices of Bucket Protection, so who can read a bucket is always a yes-or-no question. - The setting travels in the
x-amz-aclheader, which every request carries; without it, STRG answers400 InvalidRequest. - An
AccessControlPolicybody and thex-amz-grant-*headers answer501 NotImplemented, so a client knows straight away that the canned ACL is the way to set access. - The key needs Manage buckets, a permission for keys with access to all buckets.
x-amz-expected-bucket-owneris welcome and has nothing to check: a key only ever reaches buckets of its own account.
When you'd use it
- Publishing files. A website's images, a product's downloads or a dataset shared by link
live happily in a public bucket. A setup script makes the bucket
public-read, and from then on every object in it can be fetched with a plain URL, no signature needed. - Closing a bucket again. When a launch is over, or a file was shared by mistake, setting
privatemakes the bucket Protected once more - from a script or an agent, without opening the dashboard. - Tools written for Amazon S3. Clients and infrastructure tools that manage a bucket's canned
ACL as part of its configuration work as they are, as long as they ask for
privateorpublic-read.
Request
PUT /?acl HTTP/1.1
Host: my-bucket.s3.eu-central-1.strg.com
Authorization: AWS4-HMAC-SHA256 Credential=...
x-amz-date: 20260926T120000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-acl: public-read
Content-Length: 0
The path-style form is PUT /my-bucket?acl on s3.eu-central-1.strg.com -
Addressing explains both.
Permissions
The access key needs Manage buckets (buckets:write), a permission held by keys with access
to all buckets. A key without it answers 403 AccessDenied. Access keys
has the details.
public-read opens every objectThis is the same change as choosing Public under Bucket Protection in the dashboard, without
the dashboard's confirmation. public-read makes every object in the bucket, including the ones
already in it, readable by anyone without a signature - with GetObject and
HeadObject at https://s3.<region>.strg.com/<bucket>/<key> or
https://<bucket>.s3.<region>.strg.com/<key>. Listing the bucket, uploading, changing and
deleting still take an access key. The dashboard can take up to a minute to show a change made
through the API.
privateAnonymous readers can still be served an object STRG has cached for them for up to
5 minutes, since nothing is cleared when the ACL changes. An object is cached only when its own
Cache-Control lets a shared cache keep it (max-age or s-maxage above zero, and no
no-store, no-cache or private), and never for more than 5 minutes. An object stored without
a Cache-Control is never cached. Anonymous reads describes the
cache.
URI parameters
| Name | Type | Required | Description |
|---|---|---|---|
Bucket | String | Yes | The bucket whose ACL is set. |
acl | Flag | Yes | Selects the ACL subresource. Sent with no value. |
Request headers
| Name | Type | Required | Description |
|---|---|---|---|
x-amz-acl | String | Yes | The canned ACL: private or public-read. Any other canned ACL (public-read-write, authenticated-read, ...) answers 501 NotImplemented, and a request without the header answers 400 InvalidRequest. |
x-amz-grant-full-control | String | No | STRG answers 501 NotImplemented; x-amz-acl sets the bucket's access. |
x-amz-grant-read | String | No | STRG answers 501 NotImplemented; x-amz-acl sets the bucket's access. |
x-amz-grant-read-acp | String | No | STRG answers 501 NotImplemented; x-amz-acl sets the bucket's access. |
x-amz-grant-write | String | No | STRG answers 501 NotImplemented; x-amz-acl sets the bucket's access. |
x-amz-grant-write-acp | String | No | STRG answers 501 NotImplemented; x-amz-acl sets the bucket's access. |
Content-MD5 | String | No | Welcome. The request has no body, so there is nothing for it to protect. |
x-amz-sdk-checksum-algorithm | String | No | Welcome, together with the checksum header the SDK sends beside it. |
x-amz-expected-bucket-owner | String | No | Welcome, with nothing to check: an access key only ever reaches its own account's buckets. |
Request body
None. The bucket's access is set entirely by x-amz-acl, so an AccessControlPolicy document
answers 501 NotImplemented.
Response
Response headers
| Name | Description |
|---|---|
x-amz-request-id | The request ID, handy for a support request. |
Response body
None. A successful request answers 200 OK with an empty body.
Errors
These are the errors this request can return, and the situation behind each one.
| Code | HTTP status | When |
|---|---|---|
InvalidRequest | 400 | The request has no x-amz-acl header. |
NotImplemented | 501 | The request carries an AccessControlPolicy body, an x-amz-grant-* header, a canned ACL other than private or public-read, or a query parameter other than acl (presigning's X-Amz-* parameters aside). |
NoSuchBucket | 404 | The bucket does not exist, it is in a region other than the endpoint's, or the account has no storage in this endpoint's region yet. |
AccessDenied | 403 | The access key lacks Manage buckets, the account is not active, an x-amz-* header is unsigned, or the request is unsigned. |
InvalidAccessKeyId | 403 | The access key does not exist, has expired or been revoked - or it was created moments ago and is not usable yet in this region where the account already stores data, in which case the same request works shortly afterwards. |
SignatureDoesNotMatch | 403 | The request signature does not match. |
RequestTimeTooSkewed | 403 | The request time is more than 15 minutes from the server's. |
AuthorizationHeaderMalformed | 400 | The signature's credential scope names a region other than the endpoint's. |
SlowDown | 503 | Too many requests. The Retry-After header says when a retry is welcome; the AWS SDKs retry on their own. |
ServiceUnavailable | 503 | A temporary failure; the same request can be retried. |
InternalError | 500 | An unexpected failure; the same request can be retried. |
Differences from Amazon S3
The table lists each place where STRG behaves differently, and what that means for a client.
| Aspect | Amazon S3 | STRG |
|---|---|---|
| Canned ACLs | private, public-read, public-read-write, authenticated-read | private and public-read, the two choices of Bucket Protection. Any other answers 501 NotImplemented |
| Explicit grants | x-amz-grant-* headers or an AccessControlPolicy body | The canned ACL is the whole setting, so there are no grants to keep track of. Grant headers and a body answer 501 NotImplemented |
x-amz-acl | Optional, when grants or a body are sent instead | Part of every request, since it carries the setting: 400 InvalidRequest without it |
Anonymous requests to a public-read bucket | GetObject, HeadObject and ListObjects are served | GetObject and HeadObject are served, which is all a shared link needs; listing and every other operation take a signed request and answer 403 AccessDenied unsigned. Authentication has the details |
| Bucket in another region | 301 redirect with x-amz-bucket-region | 404 NoSuchBucket. A bucket is reached through its own regional endpoint |
x-amz-expected-bucket-owner | Checked against the bucket owner | Welcome, with nothing to check |
Examples
Making my-bucket public-read:
- AWS CLI
- Python (boto3)
- JavaScript (AWS SDK v3)
aws s3api put-bucket-acl \
--bucket my-bucket \
--acl public-read \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1
import boto3
s3 = boto3.client(
"s3",
endpoint_url="https://s3.eu-central-1.strg.com",
region_name="eu-central-1",
)
s3.put_bucket_acl(Bucket="my-bucket", ACL="public-read")
import { PutBucketAclCommand, S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({
endpoint: "https://s3.eu-central-1.strg.com",
region: "eu-central-1",
});
await client.send(new PutBucketAclCommand({ Bucket: "my-bucket", ACL: "public-read" }));
Making my-bucket private again - the same as choosing Protected in the dashboard:
- AWS CLI
- Python (boto3)
- JavaScript (AWS SDK v3)
aws s3api put-bucket-acl \
--bucket my-bucket \
--acl private \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1
import boto3
s3 = boto3.client(
"s3",
endpoint_url="https://s3.eu-central-1.strg.com",
region_name="eu-central-1",
)
s3.put_bucket_acl(Bucket="my-bucket", ACL="private")
import { PutBucketAclCommand, S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({
endpoint: "https://s3.eu-central-1.strg.com",
region: "eu-central-1",
});
await client.send(new PutBucketAclCommand({ Bucket: "my-bucket", ACL: "private" }));
Related
- GetBucketAcl
- PutObjectAcl
- GetObjectAcl
- GetObject and HeadObject, which read a
public-readbucket's objects without a signature - Access keys
- S3 API overview