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

17,057

Solution 1

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.

Solution 2

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.

Share:
17,057
TGuimond
Author by

TGuimond

Web Developer based in Dublin, Ireland. Mostly developing Asp.net web based applications and websites.

Updated on June 09, 2022

Comments

  • TGuimond
    TGuimond about 2 years

    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!