Put request to S3 resulting in 403 (Forbidden)

0

I set up a S3 bucket {bucketName} and an IAM user, {iamUsername}. The user has the following policies to access the bucket:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::{bucketName}",
                "arn:aws:s3:::{bucketName}/*"
            ]
        }
    ]
}

And the bucket has the bucket has the following bucket policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::012345678901:user/iamUsername"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucketName",
                "arn:aws:s3:::bucketName/*"
            ]
        }
    ]
}

Other than this, the bucket blocks all public access as recommended by AWS. I use the access key of the user to pre-sign the URL to upload a file in Flask:

s3 = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY_ID,
                          aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
                          region_name=AWS_REGION)
presigned_url = s3.generate_presigned_url(
            'put_object',
            Params={
                'Bucket': S3_BUCKET,
                'Key': random_file_name,
                'ContentType': file_type
            },
            ExpiresIn=3600  # URL expires in 1 hour
        )

I use this signed url to upload the file in react:

const uploadFile = async (signedUrl) => {
    const uploadFormData = new FormData();
    uploadFormData.append('file', selectedFile);

    try {
        await fetch(signedUrl, {
          method: 'PUT',
          body: uploadFormData
        })
        .then(response => {
          console.log(response);
          if (!response.ok) {
            console.log(response);
            throw new Error(response);
          }
          return response.json();
        })

This is resulting in a 403, like below:

body: ReadableStream
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 403
statusText: "Forbidden"
type: "cors"
url: "https://{bucketName}.s3.amazonaws.com/{fileName}?AWSAccessKeyId={key}&Signature={signature}&content-type=image%2Fjpeg&Expires=1709497547"

CORS for the bucket have been set as below:

 [
        {
            "AllowedHeaders": [
                "*"
            ],
            "AllowedMethods": [
                "GET",
                "PUT",
                "DELETE",
                "HEAD",
                "POST"
            ],
            "AllowedOrigins": [
                "*"
            ],
            "ExposeHeaders": [],
            "MaxAgeSeconds": 3600
        }
    ]

Would appreciate help in figuring out what is wrong with the approach, thanks!

2 Antworten
1
Akzeptierte Antwort

This was resolved by adding content type headers when creating the put request:

await fetch(signedUrl, {
          method: 'PUT',
          headers: { 
            'Content-Type': filetype 
          },
          body: selectedFile
        })

Credit to: https://stackoverflow.com/questions/78097844/s3-put-request-to-using-a-pre-signed-url-resulting-in-403-forbidden

Sid
beantwortet vor 2 Monaten
profile picture
EXPERTE
überprüft vor 2 Monaten
0

Hello,

Could you verify the CORS has been correctly setup and you can access using CURL ? Follow this article - https://repost.aws/knowledge-center/s3-configure-cors

AWS
EXPERTE
beantwortet vor 2 Monaten
  • Hi Ranjan,

    The CORS configuration for my bucket is:

    [
        {
            "AllowedHeaders": [
                "*"
            ],
            "AllowedMethods": [
                "GET",
                "PUT",
                "DELETE",
                "HEAD",
                "POST"
            ],
            "AllowedOrigins": [
                "*"
            ],
            "ExposeHeaders": [],
            "MaxAgeSeconds": 3600
        }
    ]
    

    However, when I try to access it using:

    curl -i http://(my-bucket).s3.amazonaws.com/cors-test.html -H "Origin: https://www.example.com"
    

    I get 403 forbidden:

    HTTP/1.1 403 Forbidden
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET, PUT, DELETE, HEAD, POST
    Access-Control-Max-Age: 3600
    Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
    x-amz-request-id: TF9YTYR36PBDQ71B
    x-amz-id-2: i/R8gtlFfsQGKyAnWWSfkE7UYxm+gcvjqvxdkTYINaZreSVx7qWI+UusYX3QHrxyddizgjGFqEE=
    Content-Type: application/xml
    Transfer-Encoding: chunked
    Date: Sun, 03 Mar 2024 23:01:52 GMT
    Server: AmazonS3
    

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen