Reputation: 303
I have written an integration for the AWS SDK in PHP to send the keys for files on an S3 bucket and retrieve a pre-signed url, which more or less follows this example. This worked perfectly except I need to now check if the file exists on s3 and return empty string if it does not.
I am doing this with my code below:
<?php
public function getUrl($key, $region, $version, $fileBucket): string
{
$this->s3Client = new Aws\S3\S3Client([
'region' => $region,
'version' => $version,
]);
if ($this->s3Client->doesObjectExist($fileBucket, $key) === false) {
return '';
}
$cmd = $this->s3Client->getCommand('GetObject', [
'Bucket' => $fileBucket,
'Key' => $key
]);
$request = $this->s3Client->createPresignedRequest($cmd, $preSignedExpiration);
$preSignedUrl = (string) $request->getUri();
return $preSignedUrl ?? '';
}
My code returned the presigned urls perfectly until I added the if statement checking the method doesObjectExist(). doesObjectExist() returns false for all of my objects on S3, and not just the ones with a $key that does not exist in the S3 bucket. So that rules out the S3 keys, buckets or api keys being invalid, which has been the answer I have come across researching this issue primarily.
Also if you happen to know a better way to do this using what is returned in $cmd or $request, without having to call doesObjectExist() (if it is possible) that would simplify my code a bit.
Edit:
The policy for the IAM user I am accessing the AWS S3 API through looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::example-dev-us-east-1-111111111111",
"arn:aws:s3:::example-dev-us-east-1-111111111111/*"
]
}
]
}
And the s3 Bucket policy looks like:
{
"Sid": "dev-web-app-get-policy",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::2222222222:role/example-dev-us-east-1-111111111111"
},
"Action": [
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::example-dev-us-east-1-111111111111",
"arn:aws:s3:::example-dev-us-east-1-111111111111/*"
]
}
So it would seem that I should be able to access the needed resources. I listed fake bucket names, for security. But I have checked that those mathc s3 in the console.
When have tried calling the the api for the HeadObject like this:
$this->s3Client->headObject([
'Bucket' => $fileBucket,
'Key' => $key
]);
And I get the following message:
"Error executing \"HeadObject\" on \"https://example-dev-us-east-1-111111111111/54bf7350-a819-41dd-9da3-3710eb8b095a-Screenshot_2021-03-09_20-15-12.png\"; AWS HTTP error: Client error: `HEAD https://example-dev-us-east-1-111111111111/54bf7350-a819-41dd-9da3-3710eb8b095a-Screenshot_2021-03-09_20-15-12.png` resulted in a `403 Forbidden` response (client): 403 Forbidden (Request-ID: XR6W77BB817407K2) - ",
"url": "/files.json"
Not sure if that helps.
Thanks!
Upvotes: 1
Views: 2142
Reputation: 78573
You need the s3:GetObject
permission to invoke the HeadObject API, which is what the PHP SDK invokes when your code calls doesObjectExist()
.
If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the s3:ListBucket permission.
- If you have the s3:ListBucket permission on the bucket, Amazon S3 returns an HTTP status code 404 ("no such key") error.
- If you don’t have the s3:ListBucket permission, Amazon S3 returns an HTTP status code 403 ("access denied") error.
So, you probably have s3:ListBucket but not s3:GetObject.
Upvotes: 2