gatsby-uc / gatsby-plugin-s3

Deploy your gatsby site to a S3 bucket.
https://gatsby-plugin-s3.jari.io/
MIT License
210 stars 110 forks source link

Document which permissions are required #39

Open jariz opened 5 years ago

jariz commented 5 years ago

We're currently suggesting people should give admin access to their IAM accounts in the README, this is probably not a very secure thing to suggest. We should figure out which exact permissions the plugin needs and document them, preferably through a JSON policy.

YoshiWalsh commented 5 years ago

I have an IAM policy with the exact permissions that I need, I'll get it later tonight. It might not cover all use cases though.

jariz commented 5 years ago

Should be a good starting point!

YoshiWalsh commented 5 years ago

Could I get some feedback on this? I'll make it pretty later, and maybe include a sample policy in JSON format too.

Required permissions:

Basic permissions

s3:HeadBucket s3:ListBucket (for the bucket) s3:GetBucketLocation (for the bucket) s3:GetObject (for all objects within the bucket)

If acl is configured as null (Recommended)

s3:PutObject (for all objects within the bucket)

If acl is not configured or is not null (Not recommended)

s3:PutObjectAcl (for all objects within the bucket)

If generateRoutingRules is true or not configured (Recommended)

s3:PutBucketWebsite (for the bucket)

If removeNonexistentObjects is true or not configured (Recommended)

s3:DeleteObject (for all objects within the bucket)

If you’re following the With CloudFront recipe and are doing automatic CloudFront invalidations (Optional)

cloudfront:CreateInvalidation cloudfront:GetInvalidation (optional)

If you are using gatsby-plugin-s3 to automatically create the bucket for you

s3:CreateBucket

svvitale commented 5 years ago

This worked for my first deploy. On subsequent deploys the upload succeeded, but S3 threw up a 403 when I tried to load the site in a browser. Updating all files to be public allowed the site to load correctly again. Removing acl: null and adding the s3:PutObjectAcl permission also resolved it.

YoshiWalsh commented 5 years ago

With acl: null, you need to add a bucket policy to allow public access. Please see this guide.

Configuring a bucket policy and disabling ACLs is recommended, because ACLs are considered legacy by Amazon. "As a general rule, AWS recommends using S3 bucket policies or IAM policies for access control. S3 ACLs is a legacy access control mechanism that predates IAM."

Source

svvitale commented 5 years ago

Yup, that worked for me. Thanks!

jariz commented 5 years ago

This looks good! @JoshuaWalsh Let's make a default sample policy and in the recipe guides, recommend people to add the additional perms to their policies.

chris-erickson commented 5 years ago

I have applied all these permissions on a new bucket, with acl: null and still am having issues getting past here:

- Retrieving bucket info...
✖ Failed.
  AccessDenied: Access Denied

I use a dedicated user for CI, and attached this policy to the user, and have the bucket policy for public access. I was able to deploy the first time, but not after that and I manually created the bucket. Do we have a concise set of steps and settings needed to get this working all the way on the first shot? I'm ok with giving this free reign on that particular bucket, the content is reproducible after all.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutAccountPublicAccessBlock",
                "s3:GetAccountPublicAccessBlock",
                "s3:ListAllMyBuckets",
                "s3:HeadBucket"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::mysite.com/*",
                "arn:aws:s3:::staging.mysite.com/*",
                "arn:aws:s3:::mysite.com",
                "arn:aws:s3:::staging.mysite.com"
            ]
        }
    ]
}

As a suggestion, it might be nice to better print debug info for non-advanced users as I had to look through the source to find what action Retrieving bucket info... was trying to take, and then look up in the docs to find what that IAM policy might look like. Seems like we could print those details in the log output upon failure, perhaps?

I'm very thankful for this package, as it really helps solve one of the most boring, and boilerplate tasks for a S3 static site. I'm so close!

jketcham commented 5 years ago

@chris-erickson I just got this setup for me and was running into similar issues. This is the IAM policy I created:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AccessToGetBucketLocation",
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:CreateBucket" <- if you want this plugin to create the bucket if it doesn't exist
            ],
            "Resource": [
                "arn:aws:s3:::*"
            ]
        },
        {
            "Sid": "AccessToWebsiteBuckets",
            "Effect": "Allow",
            "Action": [
        "s3:PutBucketWebsite",
                "s3:PutObject",
                "s3:PutObjectAcl", <- if you don't want to set acl: null
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::your-bucket.com",
                "arn:aws:s3:::your-bucket.com/*",
                "arn:aws:s3:::staging.your-bucket.com",
                "arn:aws:s3:::staging.your-bucket.com/*"
            ]
        },
        {
            "Sid": "AccessToCloudfront", <- if you want to invalidate a cloudfront distribution cache
            "Effect": "Allow",
            "Action": [
                "cloudfront:GetInvalidation",
                "cloudfront:CreateInvalidation"
            ],
            "Resource": "*"
        }
    ]
}
chris-erickson commented 5 years ago

Thanks, somehow GetBucketLocation got lost, but I still am having the same error. For me I:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutBucketWebsite",
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::mysite.com/*",
                "arn:aws:s3:::staging.mysite.com/*",
                "arn:aws:s3:::mysite.com",
                "arn:aws:s3:::staging.mysite.com"
            ]
        }
    ]
}
image

This policy is attached to the CI user which has access key/id added. 🤷‍♂️

YoshiWalsh commented 5 years ago

Hi @chris-erickson ,

My IAM policy also includes HeadBucket (not sure if this is necessary) and PutObjectAcl (which theoretically shouldn't be necessary with acl: null, but maybe this isn't working as expected). Could you please try adding these and seeing if it works correctly?

jketcham commented 5 years ago

@JoshuaWalsh the s3:ListBucket permission includes access for the HEAD Bucket operation in addition to the GET Bucket operation, you can see here: https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html#using-with-s3-actions-related-to-buckets.

And in my IAM policy, I left out the PutObjectAcl permission since I'm setting acl: null and it's working fine.

@chris-erickson for my configuration, I was also able to set all the "Manage public access control lists (ACLs)" and "Manage public bucket policies" options to true and it's working for me.

If you're still having issues, what I did to see where I was failing was to install the aws-sdk npm package, set my AWS access/secret tokens as env vars (which the sdk sees) and open up a node shell, then try running each of the s3 commands in bin.ts to see which ones failed. For me, it was the s3.getBucketLocation command, because I didn't have that permission before. You could also just try using the aws-cli commands and make sure they work.

jariz commented 5 years ago

It should show the stacktrace on errors by default, but the AWS SDK is probably throwing some weird non default error object without a stacktrace.

cesargdm commented 5 years ago

This is perfectly working, but does not make the Cloudfront invalidation.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket",
                "s3:DeleteObject",
                "s3:GetBucketLocation",
                "s3:PutBucketWebsite"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket.com",
                "arn:aws:s3:::my-bucket.com/*"
            ]
        }
    ]
}
YoshiWalsh commented 5 years ago

Something I just discovered: If you're allowing gatsby-plugin-s3 to create the bucket for you, you may also need PutBucketAcl. I imagine this isn't necessary if you've set acl: null in your config, but I haven't tested that yet.

manterfield commented 5 years ago

For frustrated developers arriving here from google...

One cause of the error:


- Retrieving bucket info...

✖ Failed.

  AccessDenied: Access Denied

Is a non-unique S3 bucket name. The plugin will attempt to get info on the bucket name you specified before doing its other work. If you don't own that bucket (since someone else already has the name you picked) it will quite rightly fail with a 403 and give you an error message that is about as much use as a chocolate tea pot.

jgcmarins commented 4 years ago

still facing:

✖ Failed.
  AccessDenied: Access Denied

after a gatsby-plugin-s3 deploy

sekerez commented 7 months ago

bump on adding this to the README