Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Denied - S3 resource using Pre Signed URL - PHP SDK

I am generating a Pre Signed URL to allow users to download files from an S3 Bucket. I am generating the URL's via the PHP SDK using the following code:

public static function get_content_link( $bucket, $key ) {

    //check response code from AWS
    require_once 'aws/aws-autoloader.php';

    $s3 = new Aws\S3\S3Client([
        'version' => 'latest',
        'region'  => 'eu-west-1',
        'credentials' => [
            'key'    => 'MY-KEY',
            'secret' => 'MY-SECRET',
        ],
    ]);

    $cmd = $s3->getCommand('GetObject', [
        'Bucket' => $bucket,
        'Key'    => $key
    ]);

    $request = $s3->createPresignedRequest($cmd, '+500 minutes');

    // Get the actual presigned-url
    $presignedUrl = (string) $request->getUri();

    return $presignedUrl;
}

The URLs are being returned as expected, for example:

https://s3-eu-west-1.amazonaws.com/MY-BUCKET-NAME/product/3166_1480009917388.mov?x-amz-content-sha256=unsigned-payload&x-amz-algorithm=aws4-hmac-sha256&x-amz-credential=akiaiqrmkn276hcpjkaq%2f20161127%2feu-west-1%2fs3%2faws4_request&x-amz-date=20161127t145603z&x-amz-signedheaders=host&x-amz-expires=30000&x-amz-signature=98eaef504f053ca56908ac49c6539c4a8b8e250d7d3a4a12460f4a806ec41c19

When I try to open any of the returned links in the browser I am getting an access denied error from S3:

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>A37839BB23186F72</RequestId>
  <HostId>
yvKTN+CN1TTNk2tqoxxm3MPOGTUSMaRYtbbEFeCzGP7ou5IYf37Z9uBESwUQWDIUR1GUuPbZyuM=
  </HostId>
</Error>

The files that I want to provide access to are in a bucket which contains folders allowing public access, by the folder I am trying to access is private (called /product/). Our bucket policy looks like this:

{
        "Version": "2008-10-17",
        "Statement": [
            {
                "Sid": "AllowPublicReadProxies",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::MY-BUCKET-NAME/proxies*"
            },
            {
                "Sid": "AllowPublicReadThumbs",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::MY-BUCKET-NAME/thumbs*"
            }
        ]
    }

It is my understanding that the purpose of creating a Pre Signed URL is to allow unauthenticated users temporary access to protected files without having to modify the bucket or folder permissions.

Has anyone got any ideas as to what I have missed or done wrong?

Thanks!

like image 783
TGuimond Avatar asked Nov 27 '16 15:11

TGuimond


2 Answers

Many thanks to @Michael-sqlbot for figuring this out for me.

It turns out I was forcing the entire URL to be lowercase when outputting the pre signed URL to the page, so AWS was returning an Access Denied error due to the fact that the resource technically didn't exist.

like image 200
TGuimond Avatar answered Nov 11 '22 20:11

TGuimond


If you're getting this error, also make sure you are not doing a GET request to the presigned url, instead of a POST request.

like image 21
Martinho Hoffman Avatar answered Nov 11 '22 22:11

Martinho Hoffman