Serverless: S3 - S3BucketPermissions - Action does not apply to any resource(s) in statement
Date: 2017-09-29 06:09:58
Learn what the "S3BucketPermissions - Action does not apply to any resource(s) in statement" error message means & how to apply permissions on S3.

I've been playing around with S3 buckets with https://serverless.com/[Serverless], and recently wrote the following code to create an S3 bucket and put a file into that bucket:

[source,javascript]
----

const AWS = require("aws-sdk");

let regionParams = { 'region': 'us-east-1' }
let s3 = new AWS.S3(regionParams);

let s3BucketName = "marks-blog-bucket";

console.log("Creating bucket: " + s3BucketName);
let bucketParams = { Bucket: s3BucketName, ACL: "public-read" };

s3.createBucket(bucketParams).promise()
  .then(console.log)
  .catch(console.error);

var putObjectParams = {
    Body: "<html><body><h1>Hello blog!</h1></body></html>",
    Bucket: s3BucketName,
    Key: "blog.html"
   };

s3.putObject(putObjectParams).promise()
  .then(console.log)
  .catch(console.error);
----

When I tried to cURL the file I got a permission denied exception:

[source,bash]
----

$ curl --head --silent https://s3.amazonaws.com/marks-blog-bucket/blog.html
HTTP/1.1 403 Forbidden
x-amz-request-id: 512FE36798C0BE4D
x-amz-id-2: O1ELGMJ0jjs11WCrNiVNF2z2ssRgtO4+M4H2QQB5025HjIpC54VId0eKZryYeBYN8Pvb8GsolTQ=
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Fri, 29 Sep 2017 05:42:03 GMT
Server: AmazonS3
----

I wrote the following code to try and have Serverless create a bucket policy that would make all files in my bucket publicly accessible:

+++<cite>+++serverless.yml+++</cite>+++

[source,yaml]
----

service: marks-blog

frameworkVersion: ">=1.2.0 <2.0.0"

provider:
  name: aws
  runtime: python3.6
  timeout: 180

resources:
  Resources:
    S3BucketPermissions:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: marks-blog-bucket
        PolicyDocument:
          Statement:
            - Principal: "*"
              Action:
                - s3:GetObject
              Effect: Allow
              Sid: "AddPerm"
              Resource: arn:aws:s3:::marks-blog-bucket

...
----

Let's try to deploy it:

[source,bash]
----

./node_modules/serverless/bin/serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.3 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
........
Serverless: Operation failed!

  Serverless Error ---------------------------------------

  An error occurred: S3BucketPermissions - Action does not apply to any resource(s) in statement.
----

D'oh! That didn't do what I expected.

I learnt that https://stackoverflow.com/questions/44228422/s3-bucket-action-doesnt-apply-to-any-resources[this message means]:

____
Some services do not let you specify actions for individual resources; instead, any actions that you list in the Action or NotAction element apply to all resources in that service. In these cases, you use the wildcard * in the Resource element.
____

To fix it we need to use the wildcard * to indicate that the s3:GetObject permission should apply to all values in the bucket rather than to the bucket itself.

Take 2!

+++<cite>+++serverless.yml+++</cite>+++

[source,yaml]
----

service: marks-blog

frameworkVersion: ">=1.2.0 <2.0.0"

provider:
  name: aws
  runtime: python3.6
  timeout: 180

resources:
  Resources:
    S3BucketPermissions:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: marks-blog-bucket
        PolicyDocument:
          Statement:
            - Principal: "*"
              Action:
                - s3:GetObject
              Effect: Allow
              Sid: "AddPerm"
              Resource: arn:aws:s3:::marks-blog-bucket/*

...
----

Let's deploy again and try to access the file:

[source,bash]
----

$ curl --head --silent https://s3.amazonaws.com/marks-blog-bucket/blog.html
HTTP/1.1 200 OK
x-amz-id-2: uGwsLLoFHf+slXADGYkqW0bLfQ7EPG/kqzV3l2k7SMex4NlMEpNsNN/cIC9INLPohDtVFwUAa90=
x-amz-request-id: 7869E21760CD50F1
Date: Fri, 29 Sep 2017 06:05:11 GMT
Last-Modified: Fri, 29 Sep 2017 06:01:33 GMT
ETag: "57bac87219812c2f9a581943da34cfde"
Accept-Ranges: bytes
Content-Type: application/octet-stream
Content-Length: 46
Server: AmazonS3
----

Success! And if we check in the AWS console we can see that the bucket policy has been applied to our bucket:

image::{{<siteurl>}}/uploads/2017/09/2017-09-29_07-06-13.png[2017 09 29 07 06 13,285]