Minimum S3 permissions for restic backups and pruning
Configure least-privilege restic S3 permissions for backup, restore, lock cleanup, forget, and prune. Includes an AWS IAM policy pattern, prefix scoping, testing, and failure guidance.

Grant the operations restic actually performs
For a normal restic repository lifecycle, the practical minimum is not simply “read and write.” Restic must locate the bucket, list objects under its repository prefix, read repository metadata and backup data, and write new packs, indexes, snapshots, and locks. If the same credential runs retention or maintenance, it must also delete objects. Start with that lifecycle, then limit it to one bucket and one repository prefix.
On Amazon S3, a typical active backup credential needs s3:GetBucketLocation, s3:ListBucket, s3:GetObject, s3:PutObject, and s3:DeleteObject. Multipart-upload permissions may also be required by the client and object size involved; use the current [restic AWS S3 IAM policy example](https://restic.readthedocs.io/en/stable/080_examples.html) as the authority for the restic version and storage workflow you operate.
The safest default for a small team is a dedicated active credential with only the permissions required for its assigned prefix, plus a separately protected recovery path. If you deliberately use an append-only writer, remove deletion permission—but accept that this writer cannot complete the usual lock-cleanup, forget, and prune lifecycle. That trade-off should be designed and tested, not discovered when retention first runs.
- List: find repository configuration, snapshots, indexes, locks, and data objects beneath the configured prefix.
- Read: open the repository configuration and retrieve indexes, snapshots, packs, and locks for backup checks or restore.
- Write: initialize a repository and upload new backup data, metadata, and locks.
- Delete: remove stale locks and reclaim unreferenced objects during
forget --pruneor other maintenance.
AWS separates bucket-level and object-level permissions
A common AccessDenied failure comes from using the right action against the wrong resource type. In AWS IAM, s3:ListBucket and s3:GetBucketLocation apply to the bucket ARN, such as arn:aws:s3:::example-backups. Object actions such as s3:GetObject, s3:PutObject, and s3:DeleteObject apply to object ARNs, such as arn:aws:s3:::example-backups/restic/prod/*.
A least-privilege policy therefore normally has two statements: one for bucket discovery and prefix-constrained listing, and one for object operations under the repository prefix. Review the [AWS documentation on S3 actions and IAM resources](https://docs.aws.amazon.com/AmazonS3/latest/userguide/security_iam_service-with-iam.html) before adapting a policy, especially if your bucket uses a different partition, an access point, a KMS key, or organization-level policies.
- Bucket ARN:
arn:aws:s3:::example-backupsfor location lookup and object listing. - Object ARN:
arn:aws:s3:::example-backups/restic/prod/*for repository data beneath one prefix. - Do not use
arn:aws:s3:::example-backups/*fors3:ListBucket; it is an object ARN, not a bucket ARN.
Scope both object access and listing to the repository prefix
Restricting object actions to bucket/prefix/* prevents the credential from reading or changing objects elsewhere in the bucket. That alone is not enough: listing is a bucket-level operation. On AWS, constrain s3:ListBucket with an s3:prefix condition so the credential can list only the repository prefix it is meant to operate.
Allow both the prefix itself and the prefix with a trailing wildcard when testing requires it—for example, restic/prod and restic/prod/*. S3 clients do not all issue list requests with exactly the same prefix value. If a narrowly scoped policy fails only at repository open or snapshot discovery, inspect the denied request in your AWS audit trail rather than broadening object access to the whole bucket.
Keep one repository prefix per recovery boundary, such as restic/production and restic/staging, rather than sharing a broad prefix across unrelated servers. This makes credential scope, incident containment, retention ownership, and recovery documentation easier to reason about.
Adapt this AWS IAM policy for one active restic repository
The following is an **illustrative template**, not a copy-and-deploy policy. Use it only after replacing the example bucket and prefix, confirming the current restic requirements, and testing against a non-production repository or disposable prefix. It covers ordinary bucket lookup, constrained listing, object reads and writes, deletion for lifecycle work, and common multipart-upload operations.
Prerequisites: an existing bucket, a chosen repository prefix such as restic/prod, and a dedicated IAM principal for the backup host. Apply the policy to that principal through your normal AWS change process. Do not put long-lived access keys in shell history, Compose files, source control, or command arguments.
- Replace
example-backupswith the bucket name and replace everyrestic/prodvalue with the exact repository prefix. - If you use SSE-KMS, an S3 Access Point, a restrictive bucket policy, VPC endpoint policy, or AWS Organizations service control policy, additional configuration may be needed outside this IAM identity policy.
- Keep bucket creation, lifecycle configuration, public-access settings, replication, and IAM administration on an administrative identity—not the backup host credential.
Policy template
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListOnlyThisResticPrefix",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::example-backups",
"Condition": {
"StringLike": {
"s3:prefix": [
"restic/prod",
"restic/prod/*"
]
}
}
},
{
"Sid": "OperateOnlyThisResticPrefix",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts"
],
"Resource": "arn:aws:s3:::example-backups/restic/prod/*"
}
]
}
Expected result: an active backup process can open and update only the repository under the assigned prefix, while forget --prune can remove objects that are no longer referenced. Failure signals matter: a failure at ListObjectsV2 generally points to the bucket-level statement or its prefix condition; a failure uploading or restoring an object generally points to the object-level ARN, an explicit deny, encryption settings, or a bucket policy.
Translate the same least-privilege model to S3-compatible storage
The permission names and administration screens differ across S3-compatible providers, but the recovery requirement is the same: a dedicated machine credential needs the object operations required for its intended repository lifecycle, scoped as narrowly as the provider supports. Do not assume an AWS IAM JSON policy can be pasted into another provider.
Provider compatibility is an operational fact to test. Configure the real endpoint, bucket, prefix, and credential on a disposable repository first; then run an actual backup, repository check, and isolated restore. A token that looks correctly limited in a web console can still fail because of endpoint configuration, unsupported condition keys, or a provider-specific API capability.
- Cloudflare R2: create an Object Read & Write S3 API token limited to the intended backup bucket, then protect the access key material shown at token creation.
- Backblaze B2: use a restricted application key with the capabilities documented for the S3-compatible workflow. Backblaze documents that some S3 SDK workflows may require
listAllBucketNamescompatibility capability in addition to operations on the selected bucket. - Wasabi: use a dedicated IAM user or sub-user with a bucket- or folder-restricted policy, then create access keys only for that identity.
- MinIO: attach an explicit policy to a dedicated user and issue an access key that inherits or further narrows that policy; operations not allowed by policy are denied.
Technical basis
First-party references
Technical claims and limitations in this guide were checked against these primary sources. Confirm version-specific behavior when designing a production recovery process.
Related from Rested
Common questions
Frequently asked questions
Does restic need s3:DeleteObject?
A normal active credential needs s3:DeleteObject for the full repository lifecycle, including lock cleanup and removing unreferenced objects during forget --prune. A deliberately append-only writer can omit delete access, but it cannot perform those tasks. Test that operating model before relying on it.
Can restic use a read-only S3 key?
A read-only key can support recovery work when it can list and read the repository prefix. Restic commands that normally take a lock may need --no-lock; use that only when you know no writer or maintenance operation is changing the repository. A read-only credential cannot initialize repositories, create backups, clean up locks, forget snapshots, or prune data.
Does restic need access to the whole S3 bucket?
No. Object permissions can normally be restricted to one repository prefix. On AWS, bucket listing remains a bucket-level action, but an s3:prefix condition can limit which keys the credential may list. Test the exact client, endpoint, and prefix because S3-compatible providers do not all implement AWS IAM conditions the same way.
Why does listing fail when object permissions look correct?
On AWS, s3:ListBucket targets the bucket ARN, while s3:GetObject, s3:PutObject, and s3:DeleteObject target object ARNs. A policy with only bucket/prefix/* object permissions cannot authorize ListObjectsV2. Check the bucket-level statement, its s3:prefix condition, and any explicit deny in bucket, endpoint, or organization policies.
Should the backup credential be allowed to create buckets?
Usually no. Create buckets through an administrative workflow, then grant the backup host only the operations needed within its repository prefix. This limits the effect of a compromised host credential and avoids creating storage in an unintended account or region.