Search code examples
amazon-web-servicesamazon-s3amazon-iamamazon-forecast

Amazon Forecast's create_dataset_import_job S3 Role Requires Star-Access to S3-Resources


I've written a Lambda function that creates a dataset import job (link to API). The Datasource property of that request requires an S3 Config item, which in turn, contains an IAM Role "that Amazon Forecast can assume to access the Amazon S3 bucket or files".

In trying to follow the principle of least access, I'd like to give that role (Cloud Formation definition below) the fewest privileges possible. I'm able to restrict its actions to only List and Get; however, it doesn't work unless I give it access to Resource: *. I'd prefer to give it access to Resource: arn:aws:s3:::my-bucket/* (or better yet Resource: arn:aws:s3:::my-bucket/path/to/my_file.csv. The error message I get (when not using Resource: *) is

An error occurred (404) when calling the HeadObject operation: Not Found

or

An error occurred (403) when calling the HeadObject operation: Forbidden

depending on whether I'm running local (via SAM CLI) or in the LAMBDA console.

¿Has anyone come across a reason why Forecast would error-out when creating a dataset import job without write only access to ALL of s3, as opposed to just one bucket, or better one file?

  CreateDatasetImportJobS3Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - forecast.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        -
          PolicyName: ReadFromBucketPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetObject
                # I'd like to be able to do this without a STAR resource;
                # however, it doesn't seem to work without
                Resource: "*"

Solution

  • s3://my-bucket/* is not the correct format. The correct format must be a valid ARN, such as arn:aws:s3:::my-bucket/*. Furthermore, when you have API actions like ListBucket, you need to list the bucket ARN not a label within that bucket. So you should really have the Resource specified as arn:aws:s3:::my-bucket.

    To be safe, I would usually put both, making your final policy:

    Resource: 
       - "arn:aws:s3:::my-bucket"
       - "arn:aws:s3:::my-bucket/*"
    

    The first resource, arn:aws:s3:::my-bucket, covers operations such as ListBucket. The second resource, arn:aws:s3:::my-bucket/*, covers operations such as GetObject (since the object itself would be under a path covered by the wildcard).