# PutObjectLockConfiguration

PutObjectLockConfiguration sets a bucket's Object Lock configuration. On a bucket without Object
Lock it turns Object Lock on; on any bucket with it, it sets, changes or removes the default
retention - a mode and a period - that every object uploaded from then on is locked with. The
configuration sent replaces the current one. [GetObjectLockConfiguration](https://docs.strg.com/s3-api/GetObjectLockConfiguration)
is its counterpart for reading the configuration back, and [Object Lock](https://docs.strg.com/object-locks)
explains what Object Lock is and how it protects your data.

**Danger:**

- **Enabling Object Lock is permanent.** A bucket with Object Lock enabled keeps it for as long as
  the bucket exists, and no request can turn it off.
- **A default retention locks every object uploaded after it is set.** A locked object version
  cannot be deleted until its retention ends, and in `COMPLIANCE` mode nobody can shorten it.
  Locked versions are billed as stored data until their lock expires, even after the object is
  deleted.

**Info: Good to know on STRG**

- A bucket is created without Object Lock, and this operation is how it gets it:
  `CreateBucket` with `x-amz-bucket-object-lock-enabled` answers `501 NotImplemented`.
- The access key needs **Read Object Lock settings** beside **Manage Object Lock**, because
  STRG reads the bucket's current configuration before every change.
- `x-amz-bucket-object-lock-token` has nothing to do: STRG enables Object Lock on an existing
  bucket without one.
- A default retention is 1 to 3,000 days, or 1 to 8 years.
- Every configuration carries `ObjectLockEnabled` set to `Enabled`, since Object Lock can be
  turned on and never off.
- The body is plain XML with the elements below and nothing else, so a typo shows up as an error
  right away instead of being dropped without a word.
- `x-amz-expected-bucket-owner` is welcome and has nothing to check: a key only ever reaches
  buckets of its own account.
- A bucket in another region answers `404 NoSuchBucket` rather than a redirect, since each bucket
  answers on its own regional endpoint.

## When you'd use it

- **Backups that cannot be wiped.** A backup tool that wants protection against ransomware or a
  mistaken cleanup creates its bucket, then enables Object Lock with a governance-mode default of,
  say, 30 days. Every nightly backup written after that is locked for its first month without the
  tool doing anything more per object.
- **Records kept for a fixed number of years.** A team that must keep invoices or audit logs for
  seven years sets a `COMPLIANCE` default of 7 years, so nobody - not even an administrator with
  every permission - can delete a record early.
- **Adjusting the default later.** When a retention policy changes, a script sends a new default
  period or mode for objects uploaded from then on, or removes the default altogether. Objects
  already locked keep their own retention either way.
- **An agent setting up a bucket.** An agent working through the
  [MCP server](https://docs.strg.com/getting-started-mcp) can call this operation too, and a human confirms each
  change unless its key was granted to act without confirmation -
  [Object Lock and agents](https://docs.strg.com/object-locks#object-lock-and-agents) has the details.

The same settings are also in the dashboard, in a bucket's Object Lock dialog -
[Enabling Object Lock in the dashboard](https://docs.strg.com/object-locks#enabling-object-lock-in-the-dashboard)
walks through it.

## Request

```http
PUT /?object-lock 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, hex>
Content-MD5: <MD5 of the body, base64>
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<ObjectLockConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <ObjectLockEnabled>Enabled</ObjectLockEnabled>
  <Rule>
    <DefaultRetention>
      <Mode>GOVERNANCE</Mode>
      <Days>30</Days>
    </DefaultRetention>
  </Rule>
</ObjectLockConfiguration>
```

Path-style, the same request is `PUT /my-bucket?object-lock` 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 Object Lock** (`bucket-object-lock:write`) and **Read Object Lock
settings** (`bucket-object-lock:read`); Manage Object Lock always comes with Read Object Lock
settings. A key limited to certain buckets can hold both too, and then reaches only those buckets;
a key without them answers `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 Object Lock configuration is set. |
| `object-lock` | Flag | Yes | Selects the Object Lock 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 | One integrity header is required | The base64 MD5 digest of the body. STRG checks it, and a digest that does not match the body answers `400 BadDigest`. |
| `x-amz-checksum-crc32`, `x-amz-checksum-crc32c`, `x-amz-checksum-crc64nvme`, `x-amz-checksum-sha1`, `x-amz-checksum-sha256` | String | One integrity header is required | A checksum of the body, which works in place of `Content-MD5`. |
| `x-amz-sdk-checksum-algorithm` | String | No | The algorithm of the `x-amz-checksum-*` header the SDK sends. Accepted. |
| `x-amz-bucket-object-lock-token` | String | No | Has nothing to do: STRG enables Object Lock on an existing bucket without a token, so the value sent is set aside. |
| `x-amz-request-payer` | String | No | Not applicable: STRG has no Requester Pays buckets. |
| `x-amz-expected-bucket-owner` | String | No | Welcome, and has nothing to check: an access key only ever reaches its own account's buckets. |

A request with neither `Content-MD5` nor an `x-amz-checksum-*` header answers
`400 InvalidRequest`. The AWS CLI and SDKs add one on their own, so there is nothing to set up.

The body travels whole. A streaming `aws-chunked` upload of the body answers
`501 NotImplemented`; the AWS CLI and SDKs never send one for this operation.

### Request body

An `ObjectLockConfiguration` document of at most 2 MiB, in plain XML. STRG reads it strictly,
so that what is saved is exactly what was sent: comments, CDATA sections, a `DOCTYPE`, processing
instructions, namespace prefixes and any attribute other than `xmlns` answer `400 MalformedXML`,
and so does any element not in this table.

| Element | Type | Required | Description |
| --- | --- | --- | --- |
| `ObjectLockConfiguration` | Container | Yes | The root element. |
| `ObjectLockEnabled` | String | Yes | `Enabled`. A document without it, or with any other value, answers `400 InvalidRequest`: Object Lock can be enabled, never disabled. |
| `Rule` | Container | No | The default retention. Without it, the bucket's default retention is removed and Object Lock stays enabled. |
| `Rule` / `DefaultRetention` | Container | Yes, in a `Rule` | The retention applied to every object uploaded without one of its own. The only element a `Rule` may contain. |
| `DefaultRetention` / `Mode` | String | Yes | `GOVERNANCE` or `COMPLIANCE`. |
| `DefaultRetention` / `Days` | Integer | One of `Days` or `Years` | The retention period in days, 1 to 3,000. |
| `DefaultRetention` / `Years` | Integer | One of `Days` or `Years` | The retention period in years, 1 to 8. |

A default retention applies to objects uploaded after it is set. Changing or removing it
releases nothing that is already locked. A legal hold is never a bucket default; it is placed on
an object of its own with [PutObjectLegalHold](https://docs.strg.com/s3-api/PutObjectLegalHold).

## Response

A successful request answers `200 OK` with no body.

### Response headers

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

`x-amz-request-charged` is never returned, since STRG has no Requester Pays buckets.

### Response body

None.

## Errors

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

| Code | HTTP status | When |
| --- | --- | --- |
| `InvalidRequest` | 400 | `ObjectLockEnabled` is missing or not `Enabled` - including on a bucket that already has Object Lock, which stays on for good - or the request carries neither `Content-MD5` nor an `x-amz-checksum-*` header. |
| `InvalidArgument` | 400 | The default retention is longer than 3,000 days or 8 years. |
| `MalformedXML` | 400 | The body is not well-formed XML; its root is not `ObjectLockConfiguration`; it contains an element not listed above; a `DefaultRetention` lacks `Mode`, has both `Days` and `Years` or neither, a period that is not a whole number of at least 1, or a mode other than `GOVERNANCE` or `COMPLIANCE`; a `Rule` is sent without `ObjectLockEnabled` set to `Enabled`; or it uses a comment, CDATA section, `DOCTYPE`, processing instruction, namespace prefix or an attribute other than `xmlns`. |
| `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. |
| `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 Object Lock** or **Read Object Lock settings**, is limited to buckets that do not include this one, or your account is not active - or the request is unsigned. |
| `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. |
| `NotImplemented` | 501 | The request carries a query parameter this operation does not accept, or sends the body as a streaming `aws-chunked` upload. |
| `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 |
| --- | --- | --- |
| Permission | `s3:PutBucketObjectLockConfiguration` in an IAM or bucket policy | **Manage Object Lock** and **Read Object Lock settings** on the access key, with no policy to write |
| Object Lock at bucket creation | `x-amz-bucket-object-lock-enabled` on `CreateBucket` | The bucket is created first, and this operation turns Object Lock on; the header on `CreateBucket` answers `501 NotImplemented` |
| `x-amz-bucket-object-lock-token` | Accepted when enabling Object Lock on an existing bucket | Not needed: STRG enables Object Lock on an existing bucket without one |
| Retention period | `Days` or `Years` | `Days` 1 to 3,000 or `Years` 1 to 8 |
| `ObjectLockEnabled` | Optional | Always present, as `Enabled` |
| Unknown elements | Ignored or refused by schema | Answered `400 MalformedXML`, so a typo shows up straight away |
| 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 |

## Examples

### Enabling Object Lock with a default retention

This enables Object Lock on `my-bucket` and locks every new object in governance mode for 30
days. On a bucket that already has Object Lock, the same request replaces its default retention.

**AWS CLI**

```bash
aws s3api put-object-lock-configuration \
  --bucket my-bucket \
  --object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"GOVERNANCE","Days":30}}}' \
  --endpoint-url https://s3.eu-central-1.strg.com \
  --region eu-central-1
```

The command prints nothing on success.

**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_object_lock_configuration(
    Bucket="my-bucket",
    ObjectLockConfiguration={
        "ObjectLockEnabled": "Enabled",
        "Rule": {"DefaultRetention": {"Mode": "GOVERNANCE", "Days": 30}},
    },
)
```

**JavaScript (AWS SDK v3)**

```javascript
import { PutObjectLockConfigurationCommand, 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 PutObjectLockConfigurationCommand({
    Bucket: "my-bucket",
    ObjectLockConfiguration: {
      ObjectLockEnabled: "Enabled",
      Rule: { DefaultRetention: { Mode: "GOVERNANCE", Days: 30 } },
    },
  }),
);
```

### Removing the default retention

A configuration without a `Rule` removes the default retention. Object Lock stays enabled, new
objects are no longer locked by default, and objects already locked stay locked. On a bucket
without Object Lock, the same request enables Object Lock with no default retention - which is
just as permanent.

**AWS CLI**

```bash
aws s3api put-object-lock-configuration \
  --bucket my-bucket \
  --object-lock-configuration '{"ObjectLockEnabled":"Enabled"}' \
  --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_object_lock_configuration(
    Bucket="my-bucket",
    ObjectLockConfiguration={"ObjectLockEnabled": "Enabled"},
)
```

**JavaScript (AWS SDK v3)**

```javascript
import { PutObjectLockConfigurationCommand, 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 PutObjectLockConfigurationCommand({
    Bucket: "my-bucket",
    ObjectLockConfiguration: { ObjectLockEnabled: "Enabled" },
  }),
);
```

## Related

- [GetObjectLockConfiguration](https://docs.strg.com/s3-api/GetObjectLockConfiguration) - reading the configuration
- [CreateBucket](https://docs.strg.com/s3-api/CreateBucket) - creating the bucket that Object Lock is then enabled on
- [GetObjectRetention](https://docs.strg.com/s3-api/GetObjectRetention) and [PutObjectRetention](https://docs.strg.com/s3-api/PutObjectRetention) - one object's retention
- [GetObjectLegalHold](https://docs.strg.com/s3-api/GetObjectLegalHold) and [PutObjectLegalHold](https://docs.strg.com/s3-api/PutObjectLegalHold) - one object's legal hold
- [Object Lock](https://docs.strg.com/object-locks)
- [Access keys](https://docs.strg.com/access-keys)
- [S3 API overview](https://docs.strg.com/s3-api/overview)
