Publii Least Privilege AWS IAM Policy

I just started using Publii, but I'm already enjoying how easy it makes creating, editing, and deploying a static blog. I love that it can deploy directly to Amazon S3, but Publii's documentation on How to host a Static Website on Amazon S3 could use a security tweak.

Step 18 in the documentation directs the reader to attach the AmazonS3FullAccess policy to the publii-users group that will be used by Publii to deploy the site to S3. This will work, but it gives the group too much power. That policy grants read, write, and delete permissions to everything you have in S3. A bad actor could use that identity to erase all of your data in S3, store files at your cost, or access anything you've uploaded.

It's a best practice to grant only the permissions needed to perform a task. So, I created a new IAM policy with the minimum set of permissions that Publii needs with access limited to the S3 bucket where you host your site.

Publii's source is available on Github, so if you took a peek at their S3 deployment class, you'd see that the class only uses five S3 actions:

Below is an IAM policy that allows only those actions on a single S3 bucket. If you want to use it in your environment, replace {BUCKET_NAME} with the name of your target Publii S3 bucket. 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::{BUCKET_NAME}"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::{BUCKET_NAME}/*"
        }
    ]
}

This policy works as of Publii version: 0.39.1 (build 15486), but it may not compatible with future versions if they add more S3 actions to the deployment class.

The first statement grants the policy permission to use the ListBucket action on {BUCKET_NAME}, and the second statement grants the permission to use the remaining actions on any object inside {BUCKET_NAME}.

The policy above is configured for a single bucket. If you want to host multiple sites using multiple buckets, you'll have to assign the resources like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::{BUCKET_1}",
                "arn:aws:s3:::{BUCKET_2}",
                "arn:aws:s3:::{BUCKET_3}"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::{BUCKET_1}/*",
                "arn:aws:s3:::{BUCKET_2}/*",
                "arn:aws:s3:::{BUCKET_3}/*"
            ]
        }
    ]
}

Want to use this policy, but not sure how to set it up on your account? Check out the supplemental blog with step-by-step instructions.

This article was updated on 19 May 2022 16:29-0400