9

I have a serverless service running with the below configuration in the serverless.yml file:

service: tableau-export-rest

custom:
  dev:
    tableauBookmarksBucket: tmt-${self:provider.stage}-tableau-bookmarks
  qa:
    tableauBookmarksBucket: tmt-${self:provider.stage}-tableau-bookmarks
  prod:
    tableauBookmarksBucket: tmt-${self:provider.stage}-tableau-bookmarks

provider:
  name: aws
  runtime: nodejs12.x
  region: eu-west-1
  stage:  ${opt:stage, 'dev'}
  timeout: 900
  memorySize: 3008
  environment:
    TABLEAU_BOOKMARKS_BUCKET: ${self:custom.${self:provider.stage}.tableauBookmarksBucket}
  iamRoleStatements:
    - Effect: Allow
      Action:
        - s3:PutObject
        - s3:GetObject
        - s3:ListBucket
      Resource: "arn:aws:s3:::${self:custom.${self:provider.stage}.tableauBookmarksBucket}/*"
    - Effect: Allow
      Action:
        - lambda:InvokeFunction
      Resource: "arn:aws:lambda:*"

functions:
  saveBookmark:
    handler: index.saveBookmark
    timeout: 30
    events:
      - http:
          path: /save-bookmark
          method: post
          cors: 
            origin: '*'

The saveBookmark function looks something like this:

  const params = {
    Bucket: process.env.TABLEAU_BOOKMARKS_BUCKET,
    Key: 'ABC123'
  }

  s3.headObject(params, (err, data) => {
    if (err) {
      console.log(err);
    } else {
      console.log(data);
    }
  })

I am for some reason getting a 403 error when attempting to HEAD a file in the bucket which does not exist. After looking into the issue I discovered that I should add the permission s3:ListBucket to the list of serverless permissions to allow the headObject method which I did. This didn't seem to have any effect as I am still getting a 403 when trying to head an object in the bucket.

The bucket is not public and when I try to use the putObject method to upload a file into the bucket it works fine. Also, when the file exists in the bucket, the headObject method works just fine with a 403.

Why would I be getting a 403 instead of a 404 when a file is not present in a bucket?

Thanks

red house 87
  • 1,837
  • 9
  • 50
  • 99

2 Answers2

14

Try changing from

iamRoleStatements:
    - Effect: Allow
      Action:
        - s3:PutObject
        - s3:GetObject
        - s3:ListBucket
      Resource: "arn:aws:s3:::${self:custom.${self:provider.stage}.tableauBookmarksBucket}/*"

to

iamRoleStatements:
    - Effect: Allow
      Action:
        - s3:PutObject
        - s3:GetObject
      Resource: "arn:aws:s3:::${self:custom.${self:provider.stage}.tableauBookmarksBucket}/*"
    - Effect: Allow
      Action: s3:ListBucket
      Resource: "arn:aws:s3:::${self:custom.${self:provider.stage}.tableauBookmarksBucket}"
jellycsc
  • 10,904
  • 2
  • 15
  • 32
2

I think you are missing GetObjectAttributes permisson. so your complete policy will look like below.

iamRoleStatements:
    - Effect: Allow
      Action:
        - s3:PutObject
        - s3:GetObject
        - s3:ListBucket
        - s3:GetObjectAttributes
      Resource: "arn:aws:s3:::${self:custom.${self:provider.stage}.tableauBookmarksBucket}/*"

here quote from official documentation

You need the relevant read object (or version) permission for this operation. For more information, see Specifying Permissions in a Policy. If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the s3:ListBucket permission.

If you have the s3:ListBucket permission on the bucket, Amazon S3 returns an HTTP status code 404 ("no such key") error.

If you don’t have the s3:ListBucket permission, Amazon S3 returns an HTTP status code 403 ("access denied") error.

The following actions are related to HeadObject:

  1. GetObject
  2. GetObjectAttributes
bSr
  • 1,410
  • 3
  • 16
  • 30