# GetBucketAcl

GetBucketAcl returns a bucket's access control list (ACL) - the list of who may do what with the
bucket. On STRG that list is always one of two canned ACLs, and it mirrors the bucket's
*Bucket Protection* setting in the dashboard: `private` when the bucket is *Protected*,
`public-read` when it is *Public*. That makes GetBucketAcl a quick, dependable way for code to
ask whether a bucket is public. The setting itself changes with [PutBucketAcl](https://docs.strg.com/s3-api/PutBucketAcl)
or in the dashboard.

**Info: Good to know on STRG**

- A bucket's ACL is always `private` or `public-read`, so there are never other grants to
  account for.
- The owner, and the owner's grant, name your STRG account.
- `x-amz-expected-bucket-owner` is welcome and has nothing to check: a key only ever reaches
  buckets of its own account.

## When you'd use it

- **Checking before sharing.** An app or an agent about to hand out a plain link to an object
  can first confirm the bucket is `public-read`, so the link works for whoever opens it - or
  confirm it is `private` before storing something that must stay that way.
- **Auditing buckets.** A nightly script that walks every bucket with
  [ListBuckets](https://docs.strg.com/s3-api/ListBuckets) can read each one's ACL and report any bucket that is public
  but should not be.
- **Tools written for Amazon S3.** Clients that read a bucket's ACL as part of showing or
  managing its settings get an answer in the shape they expect.

## Request

```http
GET /?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
```

The path-style form is `GET /my-bucket?acl` on `s3.eu-central-1.strg.com` -
[Addressing](https://docs.strg.com/s3-api/overview#addressing) explains both.

### Permissions

The access key needs **Read bucket settings** (`buckets:read-config`), which every access key
holds. A key limited to certain buckets reads the ACL of those buckets, and any other bucket
answers `403 AccessDenied`. [Access keys](https://docs.strg.com/access-keys#always-included) has the details.

### URI parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Bucket` | String | Yes | The bucket whose ACL is returned. |
| `acl` | Flag | Yes | Selects the ACL subresource. Sent with no value. |

### Request headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `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.

## Response

### Response headers

| Name | Description |
| --- | --- |
| `Content-Type` | `application/xml` |
| `x-amz-request-id` | The request ID, handy for a support request. |

### Response body

The answer is an `AccessControlPolicy` document. Its elements are:

| Element | Description |
| --- | --- |
| `Owner` | The bucket owner. `ID` and `DisplayName` both carry your STRG account ID. |
| `AccessControlList` | The grants (`Grants` in the SDKs). Always one `Grant` giving the owner `FULL_CONTROL`, plus - when *Bucket Protection* is off - one giving the `AllUsers` group `READ`. |
| `Grant` / `Grantee` | For the owner, a `CanonicalUser` grantee whose `ID` and `DisplayName` are your account ID. For public read, a `Group` grantee with `URI` `http://acs.amazonaws.com/groups/global/AllUsers`. |
| `Grant` / `Permission` | `FULL_CONTROL` for the owner, `READ` for `AllUsers`. |

Here is the answer for a bucket whose *Bucket Protection* is off (`public-read`):

```xml
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Owner>
    <ID>your-account-id</ID>
    <DisplayName>your-account-id</DisplayName>
  </Owner>
  <AccessControlList>
    <Grant>
      <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
        <ID>your-account-id</ID>
        <DisplayName>your-account-id</DisplayName>
      </Grantee>
      <Permission>FULL_CONTROL</Permission>
    </Grant>
    <Grant>
      <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
        <URI>http://acs.amazonaws.com/groups/global/AllUsers</URI>
      </Grantee>
      <Permission>READ</Permission>
    </Grant>
  </AccessControlList>
</AccessControlPolicy>
```

A *Protected* (`private`) bucket answers the same document without the `AllUsers` grant.

**Note: What `public-read` means**

With `public-read`, anyone can read the bucket's objects without signing - a
[GetObject](https://docs.strg.com/s3-api/GetObject) or [HeadObject](https://docs.strg.com/s3-api/HeadObject) on the bucket's regional
endpoint. Listing the bucket, writing to it and reading its settings, GetBucketAcl included,
still take a signed request. [Anonymous reads](https://docs.strg.com/s3-api/overview#anonymous-reads) has the details.

## Errors

These are the errors this request can return, and the situation behind each one.

| Code | HTTP status | When |
| --- | --- | --- |
| `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 is limited to other buckets, the account is not active, 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. |
| `NotImplemented` | 501 | The request carries a query parameter other than `acl` (presigning's `X-Amz-*` parameters aside). |
| `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 |
| --- | --- | --- |
| Grants | Any combination of grants to users, groups and email addresses | Owner `FULL_CONTROL`, plus `AllUsers` `READ` for a bucket whose *Bucket Protection* is off - two cases, nothing more to interpret |
| Owner | Your AWS canonical user ID | Your STRG account ID, in both `ID` and `DisplayName` |
| Anonymous requests | Allowed when `READ_ACP` is granted to everyone | Always signed: an unsigned request answers `403 AccessDenied` |
| 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

Reading the ACL of `my-bucket` in `eu-central-1`, and telling whether it is public:

**AWS CLI**

```bash
aws s3api get-bucket-acl \
  --bucket my-bucket \
  --endpoint-url https://s3.eu-central-1.strg.com \
  --region eu-central-1
```

**Python (boto3)**

```python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.eu-central-1.strg.com",
    region_name="eu-central-1",
)

acl = s3.get_bucket_acl(Bucket="my-bucket")
public = any(
    grant["Grantee"].get("URI") == "http://acs.amazonaws.com/groups/global/AllUsers"
    and grant["Permission"] == "READ"
    for grant in acl["Grants"]
)
print("public-read" if public else "private")
```

**JavaScript (AWS SDK v3)**

```javascript
import { GetBucketAclCommand, S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: "https://s3.eu-central-1.strg.com",
  region: "eu-central-1",
});

const { Grants = [] } = await client.send(new GetBucketAclCommand({ Bucket: "my-bucket" }));
const isPublic = Grants.some(
  (grant) =>
    grant.Grantee?.URI === "http://acs.amazonaws.com/groups/global/AllUsers" &&
    grant.Permission === "READ",
);
console.log(isPublic ? "public-read" : "private");
```

## Related

- [PutBucketAcl](https://docs.strg.com/s3-api/PutBucketAcl)
- [GetObjectAcl](https://docs.strg.com/s3-api/GetObjectAcl)
- [PutObjectAcl](https://docs.strg.com/s3-api/PutObjectAcl)
- [Access keys](https://docs.strg.com/access-keys)
- [S3 API overview](https://docs.strg.com/s3-api/overview) - including [anonymous reads](https://docs.strg.com/s3-api/overview#anonymous-reads)
