The Minimum IAM Policy for WordPress Media on S3
The minimum IAM policy for WordPress media on S3 allows s3:ListBucket on the bucket, and s3:PutObject, s3:GetObject, s3:DeleteObject and s3:AbortMultipartUpload on its files. That's all an offload plugin needs to upload, check, replace and remove media. Limit it to one bucket, and attach it to a user made for this site.
What's the policy?
Replace my-site-media with your bucket's name.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "OffloftListBucket",
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::my-site-media"]
},
{
"Sid": "OffloftManageFiles",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:AbortMultipartUpload"],
"Resource": ["arn:aws:s3:::my-site-media/*"]
}
]
}What does each permission do?
| Permission | Why it's needed |
|---|---|
s3:ListBucket | Finds the bucket, and tells a missing file from a forbidden one. |
s3:PutObject | Uploads files. |
s3:GetObject | Reads a file back to check it. |
s3:DeleteObject | Removes a file you delete in WordPress, and the test file. |
s3:AbortMultipartUpload | Cleans up a large upload that didn't finish. |
Why are there two resources?
s3:ListBucket acts on the bucket, so its resource has no /*. The others act on files, so theirs does. Mixing these up is the most common reason a correct-looking policy returns Access Denied.
What about public access?
This policy is about what your site can do. Whether visitors can read files is separate: a bucket policy allows s3:GetObject for everyone, on the files only.
Keep Object Ownership on Bucket owner enforced. Then you don't need s3:PutObjectAcl.
How do you apply it?
- In IAM, go to Policies → Create policy, choose JSON and paste it.
- Go to Users → Create user, choose Attach policies directly and pick your policy.
- On the user, open Security credentials and create an access key. AWS shows the secret only once.
Never use root keys for a site. AmazonS3FullAccess reaches every bucket in your account, so a compromised site could reach them all.
How do you test it?
Offloft's connection test runs through credentials, bucket, upload, read back and delete, and stops at the first failure.