Amazon S3 SDK PHP doesObjectExist() problems - php

I've re-written this question to make it clearer, since I've updated it.
I'm having trouble with the Amazon AWS S3 PHP SDK. I'm just trying to check if a file exists.
Using this PHP script:
<?php
require_once("../../../configs/config.".get_current_user().".php");
require INCLUDES_PATH . 'libraries/aws/aws-autoloader.php';
use Aws\S3\S3Client;
$client = S3Client::factory(array(
'key' => AWS_ACCESS_KEY_ID,
'secret' => AWS_SECRET_KEY
));
$key = 'profile/avatar/80745d03-c295-4205-bd82-58161f2fd2d1-320.jpg';
$result = $client->doesObjectExist( AWS_S3_BUCKET, $key );
var_dump(AWS_S3_BUCKET);
var_dump($key);
var_dump($result);
?>
This is the output:
string(19) "stage.socialite.app"
string(59) "profile/avatar/80745d03-c295-4205-bd82-58161f2fd2d1-320.jpg"
bool(false)
I know the file exists, it's here:
http://stage.socialite.app.s3.amazonaws.com/profile/avatar/80745d03-c295-4205-bd82-58161f2fd2d1-320.jpg
This is the IAM policy for the user, whose Key ID and Secret Key I'm using:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::stage.socialite.app/*",
"arn:aws:s3:::stage.socialite.app"
]
}
]
}
I've just created a new Key/Secret pair and added them to my config - what have I done wrong?

If var_dump() says bool(false) or bool(true), then it is correctly returning a boolean value. print_r() does not include detailed type information and returns an empty string for false and null values.
So does the object actually exist? Things to check on:
S3 keys do not have a leading slashes. According to your code and output above, I suspect this is the problem.
Make sure you are providing the actual S3 bucket name and not the CloudFront distribution name.
doesObjectExist() returns false if the user does not have read permissions for that object.

In addition to correct bucket location and read permissions:
If using server-side encryption you need to provide the SSE options with doesObjectExist.
$s3Client->doesObjectExist($bucket, $key, array(
'SSECustomerAlgorithm' => 'AES256',
'SSECustomerKey' => $encryptionKey,
'SSECustomerKeyMD5' => md5($encryptionKey, true)
));
Missing or incorrect SSE options will yield false return from doesObjectExist.

I found the answer on another SO post, in a comment from Carlos Castillo:
AWS PHP SDK Version 2 S3 filename encoding issue
He pointed me in the direction of a Github Issue that suggested setting the region when initializing the S3 client, this is because I'm using an S3 instance in Ireland for my dev server, not the default US servers.
So this is the solution:
$client = S3Client::factory(array(
'key' => AWS_ACCESS_KEY_ID,
'secret' => AWS_SECRET_KEY,
'region' => AWS_S3_REGION
));
Where AWS_S3_REGION is a constant set in my config file, like the Key and Secret.
Credit goes to neilscastle, Carlos and Stack Overflow for it's excellent SEO

Related

Access aws services without key & secret in php

To be clear, We have created the EC2 policy, so my site can directly access the services like Parameter store, S3, Amazon SES etc.
As of now, all of my credentials are stored on AWS Parameter Store and then site is using those credentials i.e. DB credentials, diff. API keys etc. So only hard coded credentials are the one which fetch the parameters from Parameter Store. Now client want to remove those hard coded credentials as well, that's why we have created the EC2 Policy.
Till now, we have code like below to fetch the parameters:
$config = array(
'version' => 'latest',
'region' => '*****',
'credentials' => array(
'key' => '*******',
'secret' => '******',
)
);
$s3_instance = new \Aws\Ssm\SsmClient($config);
$result = $s3_instance->getParameters([
'Names' => $credential_group,
'WithDecryption' => true
]);
//converting S3 private data to array to read
$keys = $result->toArray();
var_dump($keys);
Now the question is what i have to change in above code, so it should work without passing those credentials.
Note: I am using AWS PHP library to perform above.
Update
Further reading the documentation, https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html
Using Credentials from Environment Variables
If you don't provide credentials to a client object at the time of its instantiation, the SDK attempts to find credentials in your environment. The first place the SDK checks for credentials is in your environment variables. The SDK uses the getenv() function function to look for the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables. These credentials are referred to as environment credentials.
So after that, i have tried the below:
var_dump(getenv('AWS_ACCESS_KEY_ID'));
But it returns the bool(false). So does i need to manually setup those in environment credentials?
Which things i need to change in above code?
Update
Based on this doc: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_configuration.html#credentials
I had made below change (Removed the credentials part from array):
$config = array(
'version' => 'latest',
'region' => '*****'
);
Then system throws the below warnings:
Warning: include(Test_Role_Cognitoaccess_from_instanceRole.php): failed to open stream
Warning: include(): Failed opening 'Test_Role_Cognitoaccess_from_instanceRole.php' for inclusion (include_path='.:/usr/share/pear:/usr/share/php')
Warning: include(Test_Role_Cognitoaccess_from_instanceRole.php): failed to open stream
Warning: include(): Failed opening 'Test_Role_Cognitoaccess_from_instanceRole.php' for inclusion (include_path='.:/usr/share/pear:/usr/share/php')
As you already mentioned that you attached the policy to EC2 IAM role to access other AWS services.
You should try to create a default credential provider, this will automatically pick keys from the role.
$provider = CredentialProvider::chain(CredentialProvider::env(), CredentialProvider::ini(), CredentialProvider::instanceProfile(), CredentialProvider::ecsCredentials());
When you pass credentials directly to SsmClient and same time you have defined a role to the EC2 machine then you are making confusion for the AWS. If you have defined the permission for the EC2 instance then just do as follow:
use Aws\Ssm\SsmClient;
$client = new SsmClient(['version' => 'latest', 'region' => 'ap-southeast-2']);
$result = $client->getParameters(['Names' => ['My-SECRATE-KEY'], 'WithDecryption' => true]);
print_r($result);
Please keep in mind that permissions take a little time to propagate and in this period you will get permission error for the specific user. If you wait and let the changes take effect then mentioned code will work without any error. In my case I attached AmazonSSMReadOnlyAccess to the EC2 role and to EC2 instance. If you key/value in Parameter store is not encrypted then you can remove 'WithDecryption' => true or change it to false.

Uploading object into transfer accelerated S3 bucket using PHP

I am new to AWS. As I understand, S3 transfer acceleration uses the Cloudfront edges for fastest uploading, but I can't find the proper documentation for PHP API, for uploading object into transfer acceleration enabled bucket.
My code :
use Aws\S3\S3Client;
$S3_Client = new S3Client([
'version' => 'latest',
'region' =>'ap-south-1',
'credentials' => [
'key' => 'Accesskey',
'secret' => 'Secretkey',
],
'endpoint' => 'http://my_bucket_name.s3-accelerate.amazonaws.com'
]);
$bucket = 'my_bucket_name';
$key = 'EC2.pdf';
$SourceFile = '/path/to/the/file/EC2.pdf';
$put = $S3_Client->putObject([
'Bucket' => $bucket,
'Key' => $key,
'SourceFile' => $SourceFile
]);
I am getting the following error
The authorization header is malformed;
the region 'ap-south-1' is wrong; expecting 'us-east-1'
but my bucket is located in us-east-1 , when I change the region as
us-east-1
I am getting the following error:
The specified bucket does not exist
Instead of endpoint => ..., pass 'use_accelerate_endpoint' => True to the constructor.
There are a number of different rules that come into play when building a request to send to S3. The endpoint option provides a service endpoint, rather than a bucket endpoint, and is mostly useful for non-standard configurations.
This may be related to this discussion: https://github.com/hashicorp/terraform/issues/2774
Try the following solution -
"I had same issue, i had created the bucket previously and deleted it. I changed the name and it applied no problem."

How can I verify amazon keys on correctness programmatically?

I'm connecting to Amazon SES via this php-code
$ses = new SesClient([
'credentials' => [
'key' => KEY,
'secret' => SECRET_KEY,
],
'region' => REGION,
'version' => SES_VERSION,
]);
How can I recognize here, whether constants KEY and SECRET_KEY are valid or invalid (such as wrong, inputed with typos and so on) ?
Is there any method in AWS SDK to verify it ?
I use the Python call get_user(). With no arguments, this call will return the user name based on the access key ID. This validates that the credentials are correct. This technique is not bulletproof, but does provide a simple, quick method. You can test this concept with the CLI aws iam get-user.
Python IAM get_user()

Can't pass my credentials to AWS PHP SDK

I installed AWS PHP SDK and am trying to use SES. My problem is that it's (apparently) trying to read ~/.aws/credentials no matter what I do. I currently have this code:
$S3_AK = getenv('S3_AK');
$S3_PK = getenv('S3_PK');
$profile = 'default';
$path = '/home/franco/public/site/default.ini';
$provider = CredentialProvider::ini($profile, $path);
$provider = CredentialProvider::memoize($provider);
$client = SesClient::factory(array(
'profile' => 'default',
'region' => 'us-east-1',
'version' => "2010-12-01",
'credentials' => [
'key' => $S3_AK,
'secret' => $S3_PK,
]
));
And am still getting "Cannot read credentials from ~/.aws/credentials" error (after quite a while).
I tried 'credentials' => $provider of course, that was the idea, but as it wasn't working I reverted to hardcoded credentials. I've dumped $S3_AK and $S3_PK and they're fine, I'm actually using them correctly for S3, but there I have Zend's wrapper. I've tried ~/.aws/credentials (no ".ini") to the same result. Both files having 777 permissions.
Curious information: I had to set memory limit to -1 so it would be able to var_dump the exception. The html to the exception is around 200mb.
I'd prefer to use the environment variables, all though the credentials file is fine. I just don't understand why it appears to be trying to read the file even though I've hardcoded the credentials.
EDIT: So a friend showed me this, I removed the profile and also modified the try/catch and noticed the client seems to be created properly, and the error comes from trying to actually send an email.
The trick is just remove 'profile' => 'default' from the factory params, if this is defined we can't use a custom credentials file or environment variables. Is not documented but just works.
I'm using Sns and Sdk v3.
<?php
use Aws\Credentials\CredentialProvider;
$profile = 'sns-reminders';
$path = '../private/credentials';
$provider = CredentialProvider::ini($profile, $path);
$provider = CredentialProvider::memoize($provider);
$sdk = new Aws\Sdk(['credentials' => $provider]);
$sns = $sdk->createSns([
// 'profile' => $profile,
'region' => 'us-east-1',
'version' => 'latest',
]);
This solution will probably only work if you're using version 3 of the SDK. I use something similar to this:
$provider = CredentialsProvider::memoize(CredentialsProvider::ini($profile, $path));
$client = new SesClient([
'version' => 'latest',
'region' => 'us-east-1',
'credentials' => $provider]);
I use this for S3Client, DynamoDbClient, and a few other clients, so I am assuming that the SesClient constructor supports the same arguments.
OK, I managed to fix it.
I couldn't read the credentials file but it wasn't exactly my idea.
What was happening was that the actual client was being created successfully, but the try/catch also had the sendEmail included. This was what was failing.
About creating the client with explicit credentials: If you specify region, it will try and read a credentials file.
About the SendEmail, this is the syntax that worked for me, I'd found another one also in the AWS docs site, and that one failed. It must've been for an older SDK.

create new user IAM with aws php sdk and limit access of one bucket

i am using aws php sdk for creating bucket in S3
i want to create new user IAM using aws php sdk.. .and then i want to save userkey and acceskey. ..
I got the tutorial for limit the access to user,but not get any for creating new user.
is there any way to create new user?
Install AWS SDK - http://docs.aws.amazon.com/aws-sdk-php/guide/latest/installation.html
Create an Iam client however you like by supplying your AWS credentials. The easiest example to demonstrate is putting the credentials in the PHP file directly - See http://docs.aws.amazon.com/aws-sdk-php/guide/latest/credentials.html
Then this example will create a user
<?php
require 'vendor/autoload.php';
$iamClient = \Aws\Iam\IamClient::factory(
[
'credentials' => [
'key' => 'YOUR_ACCESS_KEY',
'secret' => 'YOUR_SECRET_KEY'
]
]
);
$result = $iamClient->createUser(
[
// UserName is required
'UserName' => 'carlton',
// Optional
'Path' => '/packager/dev/'
]
);
4.Check http://docs.aws.amazon.com/aws-sdk-php/latest/class-Aws.Iam.IamClient.html for all of the methods available on the $iamClient variable we created. A good IDE will provide code completion on $iamClient so you can see available methods that way.

Categories