ChumiestBucket
ChumiestBucket

Reputation: 1073

how to fix "ClientError: An error occurred (403) when calling the HeadObject operation: Forbidden" when trying to download file in AWS Lambda function

I'm getting "errorMessage": "An error occurred (403) when calling the HeadObject operation: Forbidden" when trying to call s3.download_file (see code below).

I've looked at numerous posts, but none of them seem to be called from AWS Lambda which is where my issue resides.

My code works locally on my machine so I'm guessing the issue involves Lambda. This Lambda function will eventually be triggered by an S3 event, but during testing, it does not work.

My IAM user has full access to S3 and Lambda.

AWS Lambda function code:

import json
import boto3
import logging

log = logging.getLogger()
log.setLevel(logging.INFO)

s3 = boto3.client('s3')


def lambda_handler(event, context):
    document_name = event['Records'][0]['s3']['object']['key']
    bucket = event['Records'][0]['s3']['bucket']['name']

    log.info('Performing stuff on {}/{}'.format(bucket, document_name))

    # download the file
    s3.download_file(
        Bucket=bucket,
        Key=document_name,
        Filename=document_name
    )

    log.info('here it is!')

    return event

(I even tried entering the information into s3.download_file explicitly instead of grabbing it from event, but to no avail. The log message confirms that it's the correct path.)

the parameters passed in the test event config:

...
"s3": {
  ...
  "bucket": {
    "name": "bucket-name",
  ...
  "object": {
    "key": "filename.pdf",

Code on local machine:

import boto3

s3 = boto3.client('s3')

s3.download_file(
  Bucket='bucket-name',
  Key='filename.pdf',
  Filename='filename.pdf'
)

I expected the file to be downloaded without error, as it was when I tested the code on my machine.

Upvotes: 4

Views: 9454

Answers (2)

Rizxcviii
Rizxcviii

Reputation: 118

As mentioned by @Putnik, here is a solution with least privilege. It's using the CDK, but it can be converted into JSON

new iam.PolicyStatement({
  actions: ["s3:ListBucket"],
  resources: [
    bucket.bucketArn
  ],
  effect: iam.Effect.ALLOW,
})
new iam.PolicyStatement({
  actions: ["s3:GetObject"],
  resources: [
    bucket.arnForObjects("*"), //limit resource further if you know what object to retrieve
  ],
  effect: iam.Effect.ALLOW,
})

Upvotes: 1

Leo
Leo

Reputation: 902

I had a similar issue, and here is my solution. When you face a 403 error while using AWS SDK or CLI, it is probably because of the permissions and policies.

You might have given full S3 permission for your Bucket to your Lambda function, but the lambda doesn't have access to the objects inside the buckets unless you specify it explicitly.

Just a minor change in your policy would solve the problem.

# Change from this:
{
    "Sid": "VisualEditor1",
    "Effect": "Allow",
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::bucket-name"
}

# To this:
{
    "Sid": "VisualEditor1",
    "Effect": "Allow",
    "Action": "s3:*",
    "Resource": [
        "arn:aws:s3:::bucket-name/*",
        "arn:aws:s3:::bucket-name"
    ]
}

Make sure this policy is added to your Lambda Function Role.

P.S: For configuring the Lambda role, you need to go to your lambda function page, then, under the Configuration tab, you will find the Permissions. Click on Permissions and on the right side, click on the role name inside the Execution role section. It will open the desired page for modifying the Lambda role. Then, you can edit one of the current policies or add new one with the permissions.

Upvotes: 3

Related Questions