Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing a AWS S3 Presigned Url returns 403 Forbidden (Nodejs)

I have a Lambda Nodejs function behind an API Gateway which successfully returns a Presigned URL:

const AWS = require('aws-sdk');
const S3 = new AWS.S3({
  apiVersion: '2006-03-01',
  signatureVersion: 'v4'
});

function getSignedUrl(id, type) {
  const key = `uploads/${id}.${type}`;
  return S3.getSignedUrl('putObject', {
    Bucket: 'example-bucket-name',
    Key: key,
    Expires: 300
  });
}

The Presigned URL may look like this:

https://example-bucket-name.s3.eu-central-1.amazonaws.com/uploads/489eb7115d0c479eaf9c3b6a01eb1893.png?Content-Type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIARTVN4TPKUACY5POZ%2F20200616%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20200616T104031Z&X-Amz-Expires=300&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEMaDGV1LWNlbnRyYWwtMSJHMEUCIQCDd%2B5hFjcBd%2FA6TEV7Se6L%2B6V8VtgCrMg0%2FbOkoGKy1wIgL20u20i%2B80rnBf49MfU1T3MQK2RQdoyQF6SwGQiYgeMq7gEIvP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARABGgwxMTA5NjAwOTAwNjkiDIcy2z8%2FpQIhMOOaZirCAUFhV6uGF%2Ff44lDl%2BaFxIt9D302gcuPaxlrgZWlRMHb%2FEdrKFJsWP%2FG7%2B6ovilKh9WmcBX1fzuVa%2BHQ6rv6OaCueMEnDOBEj%2FvJ1hrI%2FwMDF1RLVlqq7pTDp6h6hmUxPfbqXu1k8sjcFotVzXZTzR0dX6kmWl41uEvaglXjrGG3ApvviH%2BSFLdUdvK9PBgrgSlamGIhxdJN75xxBzQMELfdpPJ6QanhLEwIa%2FuMliHPliXC2fasMzFEheA3Xmik43McnMJ3DovcFOuABdae1G7uUXOSaQzGZ7IjPLLZnMFfow4SzosQHlMUurlqQATPbieC9W3McsMVwggwzZX6BcN9OJb%2B0Ag3x9pS5eLnLsEio%2FyAPZJfXzoGBH5AdZ6TAZtC5cgKy0TEebH%2F3bF4%2FiamoTQ6YcZ4f48NefoNFHcRPXl3VF%2FdINmuTSG1cNlh2svT9jAUfOgaeK7tnFAW79L38Nv7xnnFMYFpyxoUx8XVkffCXmq15dyG7rLIR0FHkJ7p4C8eEqbQzOj%2Fsj1ELFFAWPtq38ZgFnWF%2BYf6W4UrkHD9AGdUucD1qvAA%3D&X-Amz-Signature=e11f346296a979e586b8f81a9db2ef2ce58c9f7a13a4f3c31f9a0bb9997b8b81&X-Amz-SignedHeaders=host

However when testing said URL in the browser I get a SignatureDoesNotMatch. Which I guess seems fair since I want to only use this with a PUT from the application later.

Using curl or postman I however get 403 Forbidden:

curl -v -X PUT -T 489eb7115d0c479eaf9c3b6a01eb1893.png "https://example-bucket-name.s3.eu-central-1.amazonaws.com/uploads/489eb7115d0c479eaf9c3b6a01eb1893.png?Content-Type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIARTVN4TPKUACY5POZ%2F20200616%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20200616T104031Z&X-Amz-Expires=300&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEMaDGV1LWNlbnRyYWwtMSJHMEUCIQCDd%2B5hFjcBd%2FA6TEV7Se6L%2B6V8VtgCrMg0%2FbOkoGKy1wIgL20u20i%2B80rnBf49MfU1T3MQK2RQdoyQF6SwGQiYgeMq7gEIvP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARABGgwxMTA5NjAwOTAwNjkiDIcy2z8%2FpQIhMOOaZirCAUFhV6uGF%2Ff44lDl%2BaFxIt9D302gcuPaxlrgZWlRMHb%2FEdrKFJsWP%2FG7%2B6ovilKh9WmcBX1fzuVa%2BHQ6rv6OaCueMEnDOBEj%2FvJ1hrI%2FwMDF1RLVlqq7pTDp6h6hmUxPfbqXu1k8sjcFotVzXZTzR0dX6kmWl41uEvaglXjrGG3ApvviH%2BSFLdUdvK9PBgrgSlamGIhxdJN75xxBzQMELfdpPJ6QanhLEwIa%2FuMliHPliXC2fasMzFEheA3Xmik43McnMJ3DovcFOuABdae1G7uUXOSaQzGZ7IjPLLZnMFfow4SzosQHlMUurlqQATPbieC9W3McsMVwggwzZX6BcN9OJb%2B0Ag3x9pS5eLnLsEio%2FyAPZJfXzoGBH5AdZ6TAZtC5cgKy0TEebH%2F3bF4%2FiamoTQ6YcZ4f48NefoNFHcRPXl3VF%2FdINmuTSG1cNlh2svT9jAUfOgaeK7tnFAW79L38Nv7xnnFMYFpyxoUx8XVkffCXmq15dyG7rLIR0FHkJ7p4C8eEqbQzOj%2Fsj1ELFFAWPtq38ZgFnWF%2BYf6W4UrkHD9AGdUucD1qvAA%3D&X-Amz-Signature=e11f346296a979e586b8f81a9db2ef2ce58c9f7a13a4f3c31f9a0bb9997b8b81&X-Amz-SignedHeaders=host"

The Lambda function has the following Permissions:

s3:ListBucket          Allow: arn:aws:s3:::example-bucket-name
s3:GetBucketLocation   Allow: arn:aws:s3:::example-bucket-name
s3:PutObject           Allow: arn:aws:s3:::example-bucket-name/uploads/*

The S3 Bucket has the following CORS Rules:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Here is the Bucket ACL:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AWSConfigBucketPermissionsCheck",
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::example-bucket-name"
        },
        {
            "Sid": "DenyUnEncryptedTraffic",
            "Effect": "Deny",
            "Principal": {
                "AWS": "*"
            },
            "Action": "*",
            "Resource": "arn:aws:s3:::example-bucket-name/*",
            "Condition": {
                "Bool": {
                    "aws:SecureTransport": "false"
                }
            }
        }
    ]
}

Could it be that the above DenyUnEncryptedTraffic Rule is causing the 403? I tested it by removing said rule but I still get a 403.

Block all public access is On!

The bucket owner has full access to the bucket!

I have been wasting too much time on this already and really need some help!

like image 841
NJones Avatar asked Jun 16 '20 11:06

NJones


People also ask

How do you check S3 URL is valid or not?

You can simply do an HTTP head request to check whether the url exist.

Does S3 bucket need to be public for Presigned URL?

By default, all S3 objects are private. Only the object owner has permission to access them. However, the object owner can optionally share objects with others by creating a presigned URL, using their own security credentials, to grant time-limited permission to download the objects.

How does Presigned URL work S3?

S3 pre-signed URLs are a form of an S3 URL that temporarily grants restricted access to a single S3 object to perform a single operation — either PUT or GET — for a predefined time limit. To break it down: It is secure — the URL is signed using an AWS access key.

How to troubleshoot HTTP 403 Forbidden error in AWS S3?

To troubleshoot the HTTP 403 Forbidden error from the Amazon S3 console, check the following: Missing permissions to s3:PutObject or s3:PutObjectAcl. Missing permissions to use an AWS Key Management Service (AWS KMS) key. Bucket access control list (ACL) doesn't allow the AWS account root user to write objects.

What is a presigned url in AWS S3?

You can use presigned URLs to generate a URL that can be used to access your S3 buckets. When you create a presigned URL, you associate it with a specific action. You can share the URL, and anyone with access to it can perform the action embedded in the URL as if they were the original signing user.

What is a 403 error in API gateway?

Short description An HTTP 403 response code means that a client is forbidden from accessing a valid URL. The server understands the request, but it can't fulfill the request because of client-side issues. API Gateway APIs can return 403 Forbidden responses for any of the following reasons:

What is the IAM policy for AWS S3?

The following IAM policy statement requires the principal to access AWS from only the specified network range. With this policy statement in place, all access is required to originate from that range. This includes the case of someone using a presigned URL for S3.


4 Answers

Ok now I feel stupid:

Just tested said Presigned PUT URL with Postman and somehow it works:

enter image description here

Make sure you enter the Presigned URL, Select PUT and then select binary and add a file.

I will leave this up in case someone finds this useful.

like image 196
NJones Avatar answered Oct 21 '22 14:10

NJones


Be careful when you create the sign url, if the code that generates the sign url does not have the correct permission on IAM, you won't have any error when generating the pre-signed url, but you will have errors when using the URL.

like image 42
jocelyn Avatar answered Oct 21 '22 13:10

jocelyn


It can happen because your request's headers don't match the headers that you used when generating the pre-signed URL. Maybe the HTTP library that you are using adds default headers in case you did not mention one, such as Content-Type. I know that Axios does that.

like image 2
Shahar Yakov Avatar answered Oct 21 '22 12:10

Shahar Yakov


The reason why AWS returns the SignatureDoesNotMatch error (403) is usually that the secret key is incorrect

like image 1
raul7 Avatar answered Oct 21 '22 14:10

raul7