---
title: "Amazon S3 - IAM Policy"
url: https://phatdev.net/en/docs/sl-migrations/amazon-s3-policy-setup
lang: en
updated: 2026-10-20
alternate:
  vi: https://phatdev.net/docs/sl-migrations/amazon-s3-policy-setup
markdown: https://phatdev.net/en/docs/sl-migrations/amazon-s3-policy-setup.md
---

# Amazon S3 - IAM Policy

Part of the doc set: [SL Migrations](https://phatdev.net/en/docs/sl-migrations.md)

> A minimum-permission policy for the IAM user used with the plugin.

## Amazon S3 IAM Policy

> Note: the current SL Migrations build does not include Amazon S3 or other cloud storage (those SDKs were removed from this build); only Local and FTP/SFTP are available. This article is kept for reference and does not apply to the current build.

Best practice: create an IAM user with **only the minimum permissions** the plugin needs, not full S3 access.

## Policy JSON

Create the policy in IAM → Policies → **Create policy** → JSON tab:

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ListBucket",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::your-bucket-name"
        },
        {
            "Sid": "ObjectOperations",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:GetObjectAcl",
                "s3:PutObjectAcl",
                "s3:AbortMultipartUpload",
                "s3:ListMultipartUploadParts"
            ],
            "Resource": "arn:aws:s3:::your-bucket-name/*"
        }
    ]
}
```

**Replace `your-bucket-name` with your real bucket name** in both `Resource` lines.

## What each action is for

| Action | Why it is needed |
|---|---|
| `s3:ListBucket` | List the archives in the bucket (to show the backup list) |
| `s3:GetBucketLocation` | Detect the region for multipart upload |
| `s3:PutObject` | Upload the archive |
| `s3:GetObject` | Download the archive when restoring |
| `s3:DeleteObject` | Delete old backups (retention policy) |
| `s3:GetObjectAcl` + `s3:PutObjectAcl` | Set a private ACL on the archive |
| `s3:AbortMultipartUpload` | Clean up if an upload fails |
| `s3:ListMultipartUploadParts` | Resume an upload |

## Attach the policy to the user

1. Save the policy with the name `SLMigrationsS3`
2. IAM → Users → `sl-migrations-backup` → **Permissions** → **Add permissions** → **Attach policies directly**
3. Tick `SLMigrationsS3` → Next → Add

## Anti-patterns

- Do **not** attach `AmazonS3FullAccess` - it grants far more than needed
- Do **not** use a root account access key - always create a separate IAM user
- Do **not** commit the Access Key to git or a public repository

## Restrict by IP (optional, advanced)

Add a condition to the policy so it only accepts requests from your site's server IP:

```json
{
    "Condition": {
        "IpAddress": {
            "aws:SourceIp": "1.2.3.4/32"
        }
    }
}
```

If the key leaks, an attacker cannot use it from another IP. Note: the server IP must be static and must not change.

## Test the policy

After attaching the policy, go to **plugin → Storage → Test Connection**. It must PASS for List + Put + Get + Delete operations.

## See also

- [Setting up S3 step by step](https://phatdev.net/en/docs/sl-migrations/amazon-s3-step-by-step)
