I have a react application and i'm trying to use aws dynamodb, i installed the php sdk but i don't know how to query my db.
I copied the tutorial here and i changed the endpoint to: "https://dynamodb.us-west-2.amazonaws.com".
I get this error: {"__type":"com.amazon.coral.service#UnrecognizedClientException","message":"The security token included in the request is invalid."}. I guess i have to add a security token somewhere, i don't know where and neither where to find it.
Any suggestion?
Based on your error, i think you need to check your aws secret key and access key. You can try to install aws cli then create user access programmatically from aws console from this link
Then you can try your source code after that.
The following code example shows how to get an item from a DynamoDB table.
// '/path/to/aws-autoloader.php' to import AWS SDKs.
require 'vendor/autoload.php';
use Aws\DynamoDb\DynamoDbClient;
use Aws\Exception\AwsException;
use Aws\DynamoDb\Exception\DynamoDbException;
// Create an SDK class used to share configuration across clients.
$sdk = new Aws\Sdk([
'region' => 'us-west-2',
'version' => 'latest'
]);
// Use an Aws\Sdk class to create the dynamoDbClient object.
$dynamoDbClient = $sdk->createDynamoDb();
try {
$dynamoDbClient->getItem([
'Key' => [
'id' => [
'N' => 1,
],
],
'TableName' => 'products',
]);
} catch (DynamoDbException $e) {
// Catch a DynamoDb-specific exception.
echo $e->getMessage();
} catch (AwsException $e) {
// This catches the more generic AwsException. You can grab information
// from the exception using methods of the exception object.
echo $e->getAwsRequestId() . "\n";
echo $e->getAwsErrorType() . "\n";
echo $e->getAwsErrorCode() . "\n";
// This dumps any modeled response data, if supported by the service
// Specific members can be accessed directly (e.g. $e['MemberName'])
var_dump($e->toArray());
}
Notice that we did not explicitly provide credentials to the client. That’s because the SDK should detect the credentials from environment variables (via AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY), an AWS credentials INI file in your HOME directory, AWS Identity and Access Management (IAM) instance profile credentials, or credential providers.
If we don’t provide a credentials option, the SDK attempts to load credentials from your environment in the following order:
Load credentials from environment variables.
Load credentials from a credentials .ini file.
Load credentials from IAM role.
We can also directly create the service-specific client object like below:
$dynamoDbClient = new DynamoDbClient(
[
'region' => 'us-west-2',
'version' => 'latest',
]
But AWS highly recommended that you use the Sdk class to create clients if you’re using multiple client instances in your application. As per AWS docs:-
The Sdk class automatically uses the same HTTP client for each SDK
client, allowing SDK clients for different services to perform
nonblocking HTTP requests. If the SDK clients don’t use the same
HTTP client, then HTTP requests sent by the SDK client might block
promise orchestration between services.
You can refer to the AWS document pages:-
AWS SDK PHP - BASIC USAGE
AWS SDK PHP - DynamoDB Examples
AWS SDK PHP - Configuration guide
AWS SDK PHP - APIs
I hope this helps.
Related
I am running a web application on AWS Elastic Beanstalk, using PHP.
The application uses an RDS MySQL database. I would like to store the db credentials via AWS Secrets Manager.
I successfully created the secret.
Via composer, I installed the AWS PHP SDK, version 3.129. I ran the compatibility.test php file to verify my development environment. Everything was green (except for a warning not to use Xdebug for performance reasons).
Using the AWS documentation, I wrote a PHP class to get the secret values. I wrote a unit test for that class. The unit tests pass, and I was able to display the secret values with my username, password, etc. for RDS.
To provide credentials for my local development environment, I used a credentials file stored in an .aws directory. In this file, I stored:
aws_access_key_id
aws_secret_access_key
I ran my application on my local apache webserver, and it was able to successfully retrieve the RDS credentials from the AWS secrets manager, and make MySQL calls to the RDS database.
My final step was to run the application in AWS via my Elastic Beanstalk platform (which has been functioning for months, with hardcoded RDS credentials, which I want to stop using).
I looked at the AWS document which explains "Credentials for the AWS SDK for PHP Version 3". The document describes a "Default Credential Provider Chain".
I tried (unsuccessfully) using the first link in the chain, which is environment variables, following this AWS document entitled "Using Credentials from Environment Variables". The document states:
If you're hosting your application on AWS Elastic Beanstalk, you can set the AWS_ACCESS_KEY_ID and AWS_SECRET_KEY environment variables through the AWS Elastic Beanstalk console so that the SDK can use those credentials automatically.
I did so via the AWS console, using these values for my variables:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
During my testing, I tried both of my access keys, and I know they work because I use them for other purposes, and the IAM console shows recent use for both.
When I run my test, I always encounter the same exception in the AWS PHP SDK code, which reports "Cannot read credentials from /.aws/credentials".
This suggests to me that either:
The PHP SDK code is not looking for my environment variables
It tried to find them but could not
It found them but was not able to use them
When I hit the exception, I get the "Whoops" output, which shows the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables and their values exactly as I entered them.
The PHP SDK code is correct that it cannot find my credentials file because I did not upload one to Elastic Beanstalk. That way of doing it does not make sense to me in Elastic Beanstalk, though it works fine for my local environment.
Here are the last few calls in the backtrace of the exception:
Aws\Exception\CredentialsException
…/vendor/aws/aws-sdk-php/src/Credentials/CredentialProvider.php691
21
Aws\Credentials\CredentialProvider reject
…/vendor/aws/aws-sdk-php/src/Credentials/CredentialProvider.php424
20
Aws\Credentials\CredentialProvider Aws\Credentials{closure}
…/vendor/aws/aws-sdk-php/src/Middleware.php121
19
Aws\Middleware Aws{closure}
…/vendor/aws/aws-sdk-php/src/RetryMiddleware.php269
18
Aws\RetryMiddleware __invoke
…/vendor/aws/aws-sdk-php/src/Middleware.php206
17
Aws\Middleware Aws{closure}
…/vendor/aws/aws-sdk-php/src/StreamRequestPayloadMiddleware.php83
Here is the code I hit in the "Credential Provide reject":
if (!is_readable($filename)) {
return self::reject("Cannot read credentials from $filename");
}
Here is the code I wrote to get the secret (with some extraneous debugging statements which I will remove later):
public function getSecretString(): ?string
{
echo 'In getSecretString' . "\r\n";
$result = null;
$client = new SecretsManagerClient([
'profile' => 'default',
'version' => '2017-10-17',
'region' => 'us-east-2'
]);
echo 'Lets try' . "\r\n";
try {
$result = $client->getSecretValue([
'SecretId' => $this->secretName,
]);
echo 'Got a result' . "\r\n";
} catch (AwsException $e) {
echo 'FAILED!' . "\r\n";
// output error message if fails
echo $e->getMessage();
echo "\n";
}
if ($result !== null) {
echo 'We got our secret string!' . "\r\n" .
$this->secretString = $result['SecretString'];
} else {
echo 'We DID NOT get our secret string!' . "\r\n" .
$this->secretString = null;
}
print_r($this->secretString);
echo "\r\n";
return $this->secretString;
}
From my debugging it appears that the SDK simply ignores any credential provide method other than the credentials file. I have tried:
Setting local environment variables on my local machine when running the local webserver.
Setting my SDK client array to only look at the env() method.
Hardcoding my credentials.
None of these methods of setting my creds worked.
I also tried using older versions of the SDK to see if a bug was recently introduced, going as far back as 3.76.0. No difference.
Here is the revised code showing the commented out attempt #2 above, and attempt #3 above:
public function getSecretString(): ?string
{
echo 'In getSecretString' . "\r\n";
$result = null;
// Only load credentials from environment variables
//$provider = CredentialProvider::env();
$client = new SecretsManagerClient([
'profile' => 'default',
'version' => '2017-10-17',
'region' => 'us-east-2',
//'credentials' => $provider,
'credentials' => [
'key' => 'AKIAVGZKSJ5G76TTG2P4',
'secret' => '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',
],
// 'debug' => true
]);
try {
$result = $client->getSecretValue([
'SecretId' => $this->secretName,
]);
echo 'Got a result' . "\r\n";
} catch (AwsException $e) {
echo 'FAILED!' . "\r\n";
// output error message if fails
echo $e->getMessage();
echo "\n";
}
if ($result !== null) {
echo 'We got our secret string!' . "\r\n" .
$this->secretString = $result['SecretString'];
} else {
echo 'We DID NOT get our secret string!' . "\r\n" .
$this->secretString = null;
}
return $this->secretString;
}
I also tried a second way of getting the credentials via the Default chain: Assume an IAM role. I tried to follow the documentation here, but admittedly found it confusing. In my Elastic Beanstalk Security configuration, I noticed two IAM roles:
aws-elasticbeanstalk-ec2-role
aws-elasticbeanstalk-service-role
I assigned the following policies to both roles:
SecretsManagerReadWrite
IAMFullAccess (because when I assigned the previous policy, there was a note to assign this one also)
Assigning these IAM policies did not correct the problem.
My first preference is to solve this problem via the Elastic Beanstalk environment variables, since it seems extremely simple, and the AWS documentation clearly states it should work. Alternatively, solving it via IAM policies would be desirable if it does not require a lot of scripting.
How can I solve this problem?
(Posted solution on behalf of the question author, in order to move it from the question).
In my client SecretsManagerClient array, I had included the following line:
'profile' => 'default',
By stepping through the SDK code, I observed the presence of that line is interpreted to mean "look for a credentials file and skip the default chain of credentials".
I removed the line, and then the SDK processed the credentials set in my environment variables.
I am developing an web application using PHP. I am storing the user credentials on the AWS Cognito service. I am logging in the user to the Cognito using PHP SDK.
I developed the feature successfully. I tested it locally on my machine, it was working. Then I deployed it onto the staging server, it was working on the staging server as well. But when I deployed it on to the live server, it gave me this error:
(1/1) CredentialsException
Error retrieving credentials from the instance profile metadata server. (cURL error 7: Failed to connect to 169.254.169.254 port 80: Connection refused (see http://curl.haxx.se/libcurl/c/libcurl-errors.html))
This is my code
try{
$client = new CognitoIdentityProviderClient([
'version' => 'latest',
'region' => 'eu-west-2'// env('AWS_REGION', '')
]);
$result = $client->adminInitiateAuth([
'AuthFlow' => 'ADMIN_NO_SRP_AUTH',
'ClientId' => COGNITO_APP_CLIENT_ID,
'UserPoolId' => COGNITO_USER_POOL_ID,
'AuthParameters' => [
'USERNAME' => $request->email,
'PASSWORD' => $request->password,
],
]);
$auth_result = $result->get('AuthenticationResult');
$cognito_access_token = $auth_result['AccessToken'];
if(!empty($cognito_access_token))
{
//register the user
$reg_user = $this->accRepo->register($request);
if($reg_user)
{
Auth::login($reg_user);
$token = $reg_user->createToken($this->tokenTag)->accessToken;
unset($reg_user->password);
return response()->json([ 'success' => true, 'access_token' => $token, 'account' => $reg_user ], SUCCESS_RESPONSE_CODE);
}
}
}
catch(Exception $e)
{
}
I am using the exact code and setting and credentials as the local machine and the staging server for the live server. But it does not work on the live server. Working on the other environments. What might be the error? I am deploying it on Heroku.
I am not familiar with Cognito, but the error you're seeing is that your code is attempting to access the Instance Metadata available in EC2. The AWS PHP SDK has a specific order in which it attempts to locate credentials. Here is an outline of different credential methods using the PHP SDK.
So, I suspect it works on your local machine because you have an IAM profile configured using the AWS CLI aws configure command.
It most likely works on your staging server because that server has an IAM Role attached to the EC2 instance. The PHP doesn't find a locally configured IAM profile, so it then skips to attempting to access the EC2 metadata, which it does successfully, so it gets authenticated.
Now, when you deploy to Heroku, it is no longer on an EC2 instance, or in your local environment. So, your CredentialProvider fails. My suggestion would be to utilize Config Vars in Heroku, then change your code to use CredentialProvider::env() as outlined here. You would need to create an IAM user with the same role as your EC2 instance that works (or enough permissions to do what you need to do). This would allow your application to securely access Cognito from an environment external to AWS.
I'm using google vision API in one of my PHP script.
Script works well when I'm executing it through the terminal:
php /var/www/html/my_script.php
But when I want to execute it from my browser I'm getting an error 500:
PHP Fatal error: Uncaught
Google\Cloud\Core\Exception\ServiceException: {\n "error": {\n
"code": 401,\n "message": "Request had invalid authentication
credentials. Expected OAuth 2 access token, login cookie or other
valid authentication credential. See
https://developers.google.com/identity/sign-in/web/devconsole-project.",\n
"status": "UNAUTHENTICATED"\n }\n}\n
I don't get why the error message suggests me to use OAuth 2, I don't need my user to log to his google account.
My code is the following:
namespace Google\Cloud\Vision\VisionClient;
require('vendor/autoload.php');
use Google\Cloud\Vision\VisionClient;
$projectId = 'my_project_id';
$path = 'https://tedconfblog.files.wordpress.com/2012/08/back-to-school.jpg';
$vision = new VisionClient([
'projectId' => $projectId,
]);
$image = $vision->image(file_get_contents($path), ['WEB_DETECTION']);
$annotation = $vision->annotate($image);
$web = $annotation->web();
Generally speaking, you will need to provide a service account keyfile when constructing a Google Cloud client. The exception to this is if you're running on Compute Engine, or if you have Application Default Credentials setup. Since you're seeing authentication errors, neither of those appear to be the case.
To obtain a service account and keyfile, check out the documentation.
Once you have created a service account and downloaded the json keyfile, you can provide it to the client library constructor:
<?php
use Google\Cloud\Vision\VisionClient;
$vision = new VisionClient([
'projectId' => $projectId,
'keyFilePath' => '/path/to/keyfile.json'
]);
Once you provide a valid keyfile, you should be able to make authenticated requests to the Vision API.
To avoid this step, you can setup Application Default Credentials on your server or computer.
I'm in the process of migrating from Amazon S3 to Google Storage and I can't seem to get my credentials to work. Here's some sample code that I put together to test my credentials:
$client = new S3Client([
'credentials' => [
'key' => 'GOOGxxxxxxxxxxxxxxx',
'secret' => 'ZfcOTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
],
'region' => 'US',
'version' => 'latest',
'endpoint' => 'https://storage.googleapis.com',
]);
try {
$result = $client->putObject(array(
'Bucket' => 'devtest',
'Key' => 'test',
'Body' => 'Hello world'
));
echo $result['ObjectURL'];
} catch (\Aws\S3\Exception\S3Exception $e) {
// The AWS error code (e.g., )
echo $e->getAwsErrorCode() . "\n";
// The bucket couldn't be created
echo $e->getMessage() . "\n";
}
Here's what I get back:
InvalidSecurity Error executing "PutObject" on "https://storage.googleapis.com/devtest/test"; AWS HTTP error: Client error response [url] https://storage.googleapis.com/devtest/test [status code] 403 [reason phrase] Forbidden InvalidSecurity (client): The provided security credentials are not valid. - InvalidSecurityThe provided security credentials are not valid.
Incorrect Authorization header
I've tried googling 100 different combinations of this issue and can't find anything. I have Interoperability enabled, at least I think I do since I don't think I can get the key/secret without it being enabled first. And I have the Google Storage API enabled.
Any help would be greatly appreciated.
Edit: here's the Authentication Header in case that helps:
AWS4-HMAC-SHA256
Credential=GOOGGUxxxxxxxxxxx/20150611/US/s3/aws4_request,
SignedHeaders=host;x-amz-content-sha256;x-amz-date,
Signature=9c7de4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I noticed it stays "aws4_request" even when I specify 'signature' => 'v2'. Not sure if that matters.
I took a look at the S3Client code and it doesn't use the 'signature' config key as far as I can tell. The only thing I found was 'signature_version' which when set to v2, I get this error:
Unable to resolve a signature for v2/s3/US. Valid signature versions include v4 and anonymous.
I'm using Laravel 5.1 with composer package aws/aws-sdk-php version 3.0.3
Any ideas?
S3 only supports v4 signatures, and this requirement is enforced by the PHP SDK. It seems that Google Cloud Storage only supports v2 signing, so you wouldn't be able to use the same library to talk to both. Google does provide their own PHP SDK, which might make talking to Cloud Storage a bit easier.
I'm trying to use Amazon S3 to store my images.
What I've done so far is installing the AWS SDK via PEAR (link: http://docs.aws.amazon.com/aws-sdk-php-2/guide/latest/installation.html)
Then I've gone to the second step, creating a client:
<?php
// Include the SDK using the Composer autoloader
require 'vendor/autoload.php';
use Aws\S3\S3Client;
// Instantiate the S3 client with your AWS credentials and desired AWS region
$client = S3Client::factory(array(
'key' => 'your-aws-access-key-id',
'secret' => 'your-aws-secret-access-key',
));
My keys are set correctly ... .
Then I want to test all this by creating a bucket like this:
$bucket = 'my-bucket';
try{
$result = $client->createBucket(array(
'Bucket' => $bucket
));
// Wait until the bucket is created
$client->waitUntil('BucketExists', array('Bucket' => $bucket));
}
catch(Exception $e){
var_dump($e->getMessage());
}
But I always get this error:
The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.
I think my SDK isn't properly installed ... Can anyone help me with this? I'm using vagrant so I installed the AWS SDK in my root folder with this command:
sudo pear -D auto_discover=1 install pear.amazonwebservices.com/sdk
I got the message that is was installed ok.
I've also did a var_dump of my $client. The link to my response: http://pastebin.com/KqkEiKGs
Don't now if you're something with it ... (My keys are hidden)
Your error message says it - you are trying to use the name that is not unique for your bucket, you should use some more unique names. And, yes, bucket names must be unique across all of Amazon S3 (not only your account).
You can read more about it here.