# PutBucketEncryption

PutBucketEncryption sets a bucket's default server-side encryption: the encryption applied to new
objects uploaded without an encryption header of their own. On STRG that default is
server-side encryption with STRG-managed keys (`AES256`) - we look after the keys, so there is
nothing more to choose. [GetBucketEncryption](https://docs.strg.com/s3-api/GetBucketEncryption) reads the setting back.

The default applies to objects uploaded from the moment it is set. Objects already in the bucket
keep the encryption they were stored with, and an upload that brings its own key (SSE-C) is
encrypted with that key instead.

**Info: Good to know on STRG**

- `AES256` is the default there is, with the keys managed for you. SSE-KMS (`aws:kms`,
  `aws:kms:dsse`), a KMS key ID, bucket keys and blocked encryption types answer
  `501 NotImplemented`, so a client knows straight away.
- The configuration holds exactly one `Rule`.
- Every request carries an integrity header - `Content-MD5` or an `x-amz-checksum-*` header. The
  AWS SDKs and the AWS CLI send one on their own, so this is taken care of.
- Once set, the default stays: `DeleteBucketEncryption` answers `501 NotImplemented`.
- `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

- A compliance baseline asks for default encryption on every bucket. The script that sets up a
  new bucket calls PutBucketEncryption with `AES256`, and later audits confirm it with
  [GetBucketEncryption](https://docs.strg.com/s3-api/GetBucketEncryption).
- Infrastructure-as-code tools often declare a bucket's default encryption next to the bucket
  itself. With `AES256` in that declaration, they apply it here the same way they do on Amazon S3.
- An agent setting up a bucket for a new project sets the default before it writes anything, so
  every object it stores afterwards is encrypted without each upload having to ask.

## Request

```http
PUT /?encryption 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: <SHA-256 of the body>
Content-MD5: <base64 MD5 of the body>
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<ServerSideEncryptionConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Rule>
    <ApplyServerSideEncryptionByDefault>
      <SSEAlgorithm>AES256</SSEAlgorithm>
    </ApplyServerSideEncryptionByDefault>
  </Rule>
</ServerSideEncryptionConfiguration>
```

Path-style, the same request is `PUT /my-bucket?encryption` on `s3.eu-central-1.strg.com`.
[Addressing](https://docs.strg.com/s3-api/overview#addressing) describes both styles.

### Permissions

The access key needs **Manage encryption** (`bucket-encryption:write`). A key limited to
certain buckets can hold it too, and then reaches only those buckets. A key without it is
answered `403 AccessDenied`. [Access keys](https://docs.strg.com/access-keys) has the details.

### URI parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Bucket` | String | Yes | The bucket whose default encryption is set. |
| `encryption` | Flag | Yes | Selects the encryption subresource. Sent without a value. |

Any other query parameter is answered `501 NotImplemented`, so a client knows straight away that
it has no effect here.

### Request headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Content-MD5` | String | Conditional | The base64 MD5 digest of the body. Either this or an `x-amz-checksum-*` header is required, and a request with neither is answered `400 InvalidRequest`. A digest that does not match the body is `400 BadDigest`. The AWS SDKs and the AWS CLI send an integrity header on their own. |
| `x-amz-sdk-checksum-algorithm` | String | No | Accepted, with the `x-amz-checksum-*` header the SDK sends beside it. That checksum header satisfies the integrity requirement above. |
| `x-amz-expected-bucket-owner` | String | No | Welcome, and has nothing to check: an access key only ever reaches its own account's buckets. |

### Request body

A `ServerSideEncryptionConfiguration` document of at most 2 MiB. STRG reads it strictly, so
the configuration applied is exactly the one meant: XML comments, CDATA sections, processing
instructions, a DTD, namespace prefixes and any attribute other than `xmlns` answer
`400 MalformedXML`, as does any element not listed here or listed more than once. The documents
the AWS SDKs and the AWS CLI build all fit.

| Element | Type | Required | Description |
| --- | --- | --- | --- |
| `ServerSideEncryptionConfiguration` | Container | Yes | The root element. |
| `Rule` | Container | Yes | Exactly one. A second `Rule` is `400 MalformedXML`. |
| `ApplyServerSideEncryptionByDefault` | Container | Yes | The default applied to new objects. |
| `SSEAlgorithm` | String | Yes | `AES256`: server-side encryption with STRG-managed keys. `aws:kms` and `aws:kms:dsse` answer `501 NotImplemented`; any other value is `400 MalformedXML`. |
| `KMSMasterKeyID` | String | No | STRG answers `501 NotImplemented`: STRG manages the keys, so there is no KMS key to name. |
| `BucketKeyEnabled` | Boolean | No | `false` is welcome and changes nothing. `true` answers `501 NotImplemented`: bucket keys belong to SSE-KMS. |
| `BlockedEncryptionTypes` | Container | No | STRG answers `501 NotImplemented`: there is no setting for blocking encryption types. |

## Response

A successful request answers `200 OK` with an empty body.

### Response headers

| Name | Description |
| --- | --- |
| `x-amz-request-id` | The request ID, for support requests. |

### Response body

None.

## Errors

These are the errors this operation can answer, and the situation behind each.

| Code | HTTP status | When |
| --- | --- | --- |
| `MalformedXML` | 400 | The body is not well-formed, is not UTF-8, uses an XML feature STRG reads strictly (above), or does not match the schema above. |
| `InvalidRequest` | 400 | Neither `Content-MD5` nor an `x-amz-checksum-*` header was sent. |
| `BadDigest` | 400 | `Content-MD5` does not match the body. |
| `XAmzContentSHA256Mismatch` | 400 | `x-amz-content-sha256` does not match the body. |
| `MaxMessageLengthExceeded` | 400 | The body is larger than 2 MiB. |
| `NotImplemented` | 501 | The configuration asks for SSE-KMS, a KMS key ID, a bucket key or blocked encryption types, or the request carries a query parameter this operation does not accept. |
| `NoSuchBucket` | 404 | The bucket does not exist, it is in a region other than the endpoint's, or your account has no storage in this endpoint's region yet. |
| `AccessDenied` | 403 | The access key lacks **Manage encryption**, or is limited to buckets that do not include this one. |
| `InvalidAccessKeyId` | 403 | The access key does not exist, has expired or been revoked, or was created so recently that it is not yet usable in this endpoint's region - a moment later it is. |
| `SignatureDoesNotMatch` | 403 | The request signature is wrong. |
| `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 at once; a retry after the `Retry-After` interval goes through. |
| `ServiceUnavailable` | 503 | A temporary failure; a retry usually succeeds. |

## Differences from Amazon S3

A few things work a little differently on STRG, each listed here with what it means for your
requests.

| Aspect | Amazon S3 | STRG |
| --- | --- | --- |
| Algorithms | `AES256` (SSE-S3), `aws:kms`, `aws:kms:dsse` | `AES256`, server-side encryption with STRG-managed keys - one choice, with no keys for you to manage. SSE-KMS answers `501 NotImplemented` |
| `BucketKeyEnabled`, `BlockedEncryptionTypes` | Supported | Neither setting exists on STRG: `BucketKeyEnabled` `false` is welcome and changes nothing; `true` and `BlockedEncryptionTypes` answer `501 NotImplemented` |
| Removing the default | `DeleteBucketEncryption` resets the bucket to SSE-S3 | The default stays once set; `DeleteBucketEncryption` answers `501 NotImplemented` ([Other S3 operations](https://docs.strg.com/s3-api/overview#other-s3-operations)) |
| Integrity header | `Content-MD5` or a checksum | The same, on every request - the SDKs send one by default |
| Request body | Any document valid against the schema | Read strictly, at most 2 MiB: comments, CDATA, a DTD and namespace prefixes answer `400 MalformedXML` |
| Bucket in another region | `301` redirect with `x-amz-bucket-region` | `404 NoSuchBucket`. Each bucket answers on its own regional endpoint. |
| `x-amz-expected-bucket-owner` | Checked against the bucket owner | Welcome, with nothing to check: a key only ever reaches buckets of its own account |

An object uploaded before the default was set can be encrypted by copying it onto itself with
[CopyObject](https://docs.strg.com/s3-api/CopyObject), sending `x-amz-server-side-encryption: AES256`. Since every bucket
keeps every version, the copy becomes the current version and the earlier one stays, billed as
stored data, until it is deleted or a [lifecycle policy](https://docs.strg.com/lifecycle-policies) removes it.

## Examples

Each example sets `AES256` as the default encryption of `my-bucket`.

**AWS CLI**

```bash
aws s3api put-bucket-encryption \
  --bucket my-bucket \
  --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}' \
  --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",
)

s3.put_bucket_encryption(
    Bucket="my-bucket",
    ServerSideEncryptionConfiguration={
        "Rules": [
            {"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}},
        ],
    },
)
```

**JavaScript (AWS SDK v3)**

```javascript
import { PutBucketEncryptionCommand, 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 PutBucketEncryptionCommand({
    Bucket: "my-bucket",
    ServerSideEncryptionConfiguration: {
      Rules: [{ ApplyServerSideEncryptionByDefault: { SSEAlgorithm: "AES256" } }],
    },
  }),
);
```

## Related

- [GetBucketEncryption](https://docs.strg.com/s3-api/GetBucketEncryption) - reading the default back
- [PutObject](https://docs.strg.com/s3-api/PutObject) - per-object encryption headers, including your own key (SSE-C)
- [CopyObject](https://docs.strg.com/s3-api/CopyObject) - re-encrypting an existing object
- [Access keys](https://docs.strg.com/access-keys)
- [S3 API overview](https://docs.strg.com/s3-api/overview)
