Search code examples
phpamazon-web-servicesamazon-s3aws-php-sdk

AWS PHP SDK 3.36 GetObject method throwing SignatureDoesNotMatch error


We are currently unable to download objects from S3, using the AWS PHP SDK v. 3.36. via the GetObject method.

We are seeing the following error:

Error executing "GetObject" on "<object path>";
AWS HTTP error: Client error: `GET <object path>` resulted in a `403 Forbidden` response:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>SignatureDoesNotMatch</Code>
  <Message>The request signature we calcul (truncated...)  SignatureDoesNotMatch (client): The request signature we calculated does not match the signature you
    provided. Check your key and signing method.
    - <?xml version="1.0" encoding="UTF-8"?>
      <Error>
        <Code>SignatureDoesNotMatch</Code>
        <Message>The request signature we calculated does not match the signature you provided.
          Check your key and signing method.

<remaining message redacted>

S3 Client setup:

public function __construct($key, $secret, $region='us-east-1') {
    $this->key = $key;
    $this->secret = $secret;
    $this->handler = new S3Client([
        'credentials' => [
            'key'    => $key,
            'secret' => $secret
        ],
        'region' =>$region,
        'version' => '2006-03-01'
    ]);
}

Call to GetObject method:

public function getFile($bucket, $sourcefile, $saveToDestination = null) {
    $getarray = array(
        'Bucket' => $bucket,
        'Key' => $sourcefile,
    );

    if ($saveToDestination) {
        $getarray['SaveAs'] = $saveToDestination;
    }

    return $this->handler->getObject($getarray);

}

For the IAM user in question, full access to S3 is provided and the credentials used above have been verified.

IAM policy (AmazonS3FullAccess):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "*"
        }
    ]
}

Solution

  • It turns out that, in v3 of the AWS PHP SDK, if there are additional bucket subpaths in between the provided bucket and key parameters, this failure gets seen.

    The following code was added to the method that calls the getFile method above:

    protected function getS3File($s3_bucket, $s3_key){
    
             /// if the bucket contains additional paths, S3 will choke
             if (strpos($s3_bucket, '/')!==false){
                 $paths = explode('/', $s3_bucket);
                 $s3_bucket = array_shift($paths);
    
                 /// so prepend them to the key!
                 $s3_key=implode('/', $paths) .'/'.$s3_key;
             }
    
             return $this->makeTempFile($this->s3Handler->getFileContents($s3_bucket, $s3_key));
          }