Unable to instantiate \Aws\Ec2\Ec2Client - php

Trying to instantiate ec2client w.r.t
$ec2Client = \Aws\Ec2\Ec2Client::factory(array(
'profile' => 'default',
'region' => 'us-west-2',
'version' => '2014-10-01'
));
but fails with error
Uncaught exception 'Aws\Common\Exception\CredentialsException' with message 'Could not load credentials.'
I have :
cat ~/.aws/credentials
[default]
aws_access_key_id = xxxxxxxxxxx
aws_secret_access_key = xxxxxxxxxxx
I am using aws-sdk through composer "aws/aws-sdk-php": "3.*#dev".
Edit 1): I am trying this on my local development machine.
Edit 2):
I tried this:
use Aws\Common\Credentials\InstanceProfileProvider;
$profile= new InstanceProfileProvider(['profile'=>'default']);
$ec2Client = \Aws\Ec2\Ec2Client::factory(array(
'region' => 'us-west-2',
'version' =>'2014-10-01',
'credentials' => $profile
));
This gives me different error :
'Error retrieving credentials from the instance profile metadata server. When you are not running inside of Amazon EC2, you must provide your AWS Access Key ID and Secret Access Key in the "key" and "secret" options when creating a client or provide an instantiated Aws\Common\Credentials\CredentialsInterface object. (cURL error 28: Connection timed out after 1000 milliseconds)' in .. /InstanceProfileProvider.php:9 ..
This gives me the impression that credential profiles are only when application running from within the AWS cloud instance ! Which makes the idea of profiles useless (which where intended for dev environment )
Edit 3)
After debugging this, It seems that sdk with credential profiles is broken or not as expected . Both credential profiles and environment variable both depends on environment variables . If environment variables are disabled, both will fail.
Possible work around:
a) Enable environment variables
b) Set HOME evn variable
putenv('HOME=/Users/yourname');
$ec2Client = \Aws\Ec2\Ec2Client::factory(array(
'region' => 'us-west-2',
'version' => '2014-10-01'
));
Profile init() function has filename option but there is not apparent way to pass credentails profile path other than HOME env variable
Aws\Common\Credentails\Profiler->init()
public static function ini($profile = null, $filename = null){
...
}
Again if you are unable to read the /Users/yourname/.aws/credentials file you have to tweak it little bit
chmod 644 /Users/yourname/.aws/credentials

You should place the .aws/credentials file in the root of your web service, not in the root of your ssh user

You have to place the .aws/credentials file with your configuration in the home directory of the web service.
Put this into some PHP file of your website
echo getenv('HOME');
then in that directory:
mkdir .aws
touch credentials
nano credentials
And there you have to paste the content (no need for quotes in the keys):
[default]
aws_access_key_id = xxxxxxxxxxx
aws_secret_access_key = xxxxxxxxxxx
And that should do it!
Edit:
As sakhunzai says in the comment (thanks!), echo getenv('HOME') can return null sometimes, if that happens he offer this solution: "However from command line php -i |grep HOME gives me correct user home directory"
So have that in mind.

Related

Laravel8 laravelcollective/remote can I create a dynamic connection

I'm migrating our inhouse backup app onto Laravel8, so far so good. I'm interested in using the laravelcollective/remote facade (SSH) to ssh onto the remote server and run some commands which it looks like this would be very good at (rather than using php exec() methods the current backup app uses).
My question however is, can i build an array/object from the database and use these details as a connection without having to manually maintain the config/remote.php file? Maintaining this with any server changes will be a nightmare to maintain as we frequently update users and sites are added removed on a regular basis! any ideas? As mentioned we are storing the ssh creds in the database which is populated via a connection form within the app.
I've built a simple test function in a controller and stepped into this with my debugger. I expected to see the array/object which is created from the config/remote file and was planning to just add new items but i couldn't find any array/objects containing the default empty production config set as default in the config/remote.php file.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use SSH;
class SecureServerController extends Controller
{
public function test() {
SSH::into()->run([
'cd /var/www',
'git pull origin master'
], function($line)
{
echo $line.PHP_EOL;
});
}
}
The following is the route used:
use App\Http\Controllers\SecureServerController;
Route::get('/test', [SecureServerController::class, 'test']);
thanks
*** EDIT ***
SO I had a look at the code for the SSH facade and found I could create a config file and pass this via the connect function:
$config = [
'host' => '123.123.123.123',
'username' => 'the-user',
'password' => 'a-password'
];
SSH::connect($config)->run([
'cd /var/www',
'git pull origin master'
], function($line)
{
echo $line.PHP_EOL;
});
However i see no way to use any port except 22. almost all our servers use a non default port as an additional level of obfuscation.

Cannot read credentials from /.aws/credentials - PHP script call AWS-SDK

I've looked at every answer on here and it seems my problem is a little different or there hasn't been a proper solution. I'm doing the following in my PHP file:
use Aws\Route53\Route53Client;
$client = Route53Client::factory(array(
'profile' => 'default',
'region' => 'us-east-1',
'version' => '2013-04-01'
));
Getting this error:
Fatal error: Uncaught Aws\Exception\CredentialsException: Cannot read credentials from /.aws/credentials
Seems like the easy fix would be ensure that the HOME directory is the right one. Indeed it already is. Files are readable and my ec2-user is already the owner. Key and Secret is already installed in the 'credentials' file. Profile name is already set to 'default.' Tried to copy /.aws to other directories such as the root, /home, etc and changed permissions, chmod, all the above. Still nothing.
Then I tried to hard-code the credentials (I know -- not recommended) just to give it a little kick, and it completely ignores that I did this:
$client = Route53Client::factory(array(
'profile' => 'default',
'region' => 'us-east-1',
'version' => '2013-04-01',
'credentials' => [
'key' => $key,
'secret' => $secret,
]
));
As a last resort, I even tried including the CredentialProvider class, and passing this into my array -- still nothing:
'credentials' => CredentialProvider::ini('default', '/home/ec2-user/.aws/credentials'),
What on earth am I doing wrong?
Just remove 'profile' => 'default', and you should work fine
$client = Route53Client::factory(array(
'region' => 'us-east-1',
'version' => 'latest',
'credentials' => [
'key' => $key,
'secret' => $secret,
]
));
Running on AWS Centos 7, I tried everything (chmod/chown /root /home/user, env, bashrc, etc) to get the /.aws/credentials to work outside the apache /var/www directory. The SDK reported that it could not read the credentials file.
I looked at PHP to see if I could set/override the HOME variable and it still did not read the credentials file until I placed the .aws folder in the '/var/www' folder and set the HOME variable in my php file like so:
<%php
putenv('HOME=/var/www');
//ZIP File SDK Install requires aws-autoloader
require 'aws-autoloader.php'; //Your php code below
Facing this issue, here was my exact approach:
PHP version : 7.2.24 AWS PHP SDK version: 3.180.4
First copy your existing aws folder to your root home directory
sudo cp -r ~/.aws /
Then your code should look like:
$client = Route53Client::factory(array(
'profile' => 'default',
'region' => 'us-east-1',
'version' => '2013-04-01'
));
In my case, it was interesting to realize that the PHP SDK looks for the credentials file in the root folder and not in the current users's home directory. That's the most feasible reason why my approach worked.
However, you want to find a more general place for your local configs and use the following approach to load it.
$path = '/my/config/folder/.aws/credentials';
$provider = CredentialProvider::ini('default', $path);
$provider = CredentialProvider::memoize($provider);
$client = Route53Client::factory(array(
'region' => 'us-east-1',
'version' => '2013-04-01',
'credentials' => $provider
));
Hopefully this throws more light into the AWS PHP community. It's really important to get this configuration right to build secure PHP applications
Here is what I ended up doing for purposes of this question, although EJ's answer above is actually the right answer. Hopefully this helps someone to get their credentials file to be read:
use Aws\Credentials\CredentialProvider;
use Aws\Route53\Route53Client;
$profile = 'default';
$path = '/var/www/html/.aws/credentials';
$provider = CredentialProvider::ini($profile, $path);
$provider = CredentialProvider::memoize($provider);
$client = Route53Client::factory(array(
'region' => 'us-east-1',
'version' => '2013-04-01',
'credentials' => $provider
));
Not sure what you are doing wrong, but I'd suggest bypassing the problem altogether and assigning an EC2 Instance role to the vm in question and then you won't have to worry about it; it's a better/more secure solution.
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
I think the AWS manual is a bit confusing.
I created the .aws directory at the filesystem root (/), not in the /root or /home dir, and everything worked.
/.aws/credentials
I upgraded from PHP 8.0 to PHP 8.1 and PHP suddenly complained it couldn't find the credential file. The xdebug error trace showed me the expected location, which was one level below my public html directory. I don't know why it changed, but I simply ran this command in that directory:
ln -s /.aws/ .aws
The symlink I created works fine to provide the credentials. I'm back up and running.
check the permission of .aws/* files using "ls -l"
Change the permission to grand read or grant all permision "sudo chmod 777 .aws/*"
rerun the code

Google - App Engine - API PHP - Warning: mkdir(): The local filesystem is readonly, mkdir failed - Allow local filesystem to make directory

The google-api-php-client library has a file named File.php, and that file is in the src/Google/Cache directory. That file returns an error from line 149:
if (! mkdir($storageDir, 0755, true)) {
The error is:
Warning: mkdir(): The local filesystem is readonly, mkdir failed in C:\Users\NoName\Documents\academic-being-90217\google-api-php-client\src\Google\Cache\File.php on line 149
I'm testing code by running it from Google App Engine Launcher on my local computer.
Obviously, my local filesystem won't allow PHP to make a directory. How can I allow PHP to make the directory? I'm using windows 7.
In the PHP documentation, it states:
Note:
mode is ignored on Windows.
In the Client.php file, the Google_Client class has a method isAppEngine(). As a test, I ran that method (locally from my computer) and it returned nothing. So, . . . on my computer, testing an App Engine project, the google-api-php-client doesn't detect that this is for App Engine. If it were running on App Engine, when the $config object is created, it checks if the code is running on App Engine, and
// Automatically use Memcache if we're in AppEngine.
if ($this->isAppEngine()) {
// Automatically use Memcache if we're in AppEngine.
$config->setCacheClass('Google_Cache_Memcache');
}
So, I'm wondering if the reason that the code is trying to create a new directory on my computer, is to use it for Cache, because it didn't detect that the code is running on App Engine. (which it isn't)
I guess I could deploy a development project to App Engine, and test the OAuth2 functionality with echo statements. I'd need to constantly be deploying every time I wanted to test. If the OAuth is working, obviously I won't need to change anything. But how will I test new versions locally on my machine, if I can't authorize OAuth2?
I deployed the following code to App Engine, and ran the code from the server. It did not display an error to the browser. Then I refreshed the window, and got a msg from inside an IF check, that the service token had been set. So, it looks like it's authorizing my app as a service. So, I'm assuming that because I ran the code from App Engine, it used Mem Cache instead of creating a Cache directory, and saving data to a file.
<?php
session_start();
//The php file loaded below outputs information to the user in the browser
include_once "templates/base.php";
//The autoload.php file loads the entire API library I think. It avoids needing to call specific files.
require_once realpath(dirname(__FILE__) . '/google-api-php-client/src/Google/autoload.php');
//The following three lines are the credentials
$client_id = 'my ID here.apps.googleusercontent.com'; //Client ID
$service_account_name = 'My name here#developer.gserviceaccount.com'; //Email Address
$key_file_location = 'Test Project-file-name.p12'; //key.p12
//Display a page header to the user in their browser
echo pageHeader("Service Account Access");
//Check if the credentials are present and assigned to their variable names
if (!strlen($client_id)
|| !strlen($service_account_name)
|| !strlen($key_file_location)) {
echo missingServiceAccountDetailsWarning();
}
//The Google_Client Class is in file Client.php
//Create a Google_Client object and use it to acquire an access token
$client = new Google_Client();
/*
foreach($client as $key => $value) {
echo $key." - ".'<br>';
}
*/
//The object $client was just created in the above line of code. Call the function 'setApplicationName' that is inside of
//the $client object.
$client->setApplicationName("Client_Drive_Examples");
$service = new Google_Service_Drive($client);
/************************************************
If we have an access token, we can carry on.
Otherwise, we'll get one with the help of an
assertion credential. In other examples the list
of scopes was managed by the Client, but here
we have to list them manually. We also supply
the service account
************************************************/
if (isset($_SESSION['service_token'])) {
echo 'There is a service token';
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
//echo 'the $key: ' . $key;
//echo '$service_account_name: ' . $service_account_name;
/*
https://www.googleapis.com/auth/drive - View and manage the files in your Google Drive
https://www.googleapis.com/auth/drive.file - View and manage files that you have created with this app
https://spreadsheets.google.com/feeds/ - Manage your spreadsheets
*/
$scopes = array('https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.file');
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
$scopes,
$key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
echo 'end of code';
?>
App Engine does not support creating directories dynamically.
It sort of does tho. You just add your directory paths to the filename and it has a new long filename, but it accomplishes the same thing, keeping you backward compatible with the older max files per folder type of filesystem assuming you branch your code for environment

RiakCS S3 PHP client library

Is there any RiakCS S3 PHP client library out there? The best I could find was S3cmd command line client software.
Also I've seen there is Riak PHP Client, but it looks like there is nothing related to S3.
I've installed aws-sdk-php-laravel and used same credentials as for RiakCS S3 but it doesn't seem to work. Error message below:
The AWS Access Key Id you provided does not exist in our records.
Thank you for any guidance or advice.
Actually, if you are using Riak, it wouldn't be a proxy, it would be a completely different endpoint. So you should do it this way with the base_url option:
$s3 = S3Client::factory([
'base_url' => 'http://127.0.0.1:8080',
'region' => 'my-region',
'key' => 'my-key',
'secret' => 'my-secret',
'command.params' => ['PathStyle' => true]
]);
Using 'command.params' allows you to set a parameter used in every operation. You will need to use the 'PathStyle' option on every request to make sure the SDK does not move your bucket into the host part of the URL like it is supposed to do for Amazon S3.
This is was all talked about on an issue on GitHub.
aws-sdk-php-laravel uses aws-sdk-php which is hard coded to use Amazon's URLs. If you want to use that library with Riak CS, you'll need to configure it to use your node as a proxy. According to the config docs that would be set using:
use Aws\S3\S3Client;
$s3 = S3Client::factory(array(
'request.options' => array(
'proxy' => '127.0.0.1:8080'
)
));
I haven't used Laravel, so I'm not sure where to put that so that it will pass the setting along to

Laravel not creating log file.

I'm learning Laravel 4.0 to develop a webserver.
I'm using a LAMP stack (Apache 2, php 5.5).
I can't find the log file where Log::error() calls writes to.
As far as I know it's supposed to be to app/storage/logs/log-cli-.txt but there are no files there.
Here is the code:
app/commands/MsgCommand.php
public function fire(){
Log::error('messages - log');
}
It's called from artisan:
app/start/artisan.php
Artisan::add(new MsgCommand());
Am I looking in the right place?
How can I check that this is indeed the right folder (i.e. where is it configured)? To check for faulty installation or setup.
Thanks to marcanuy, I am now sure it is writing to app/storage/logs.
Also I found out it writes fine if I call the command through artisan. Running on apache 2 nothing happens though. I'm starting to think I set up the command wrong.
By default app/storage is the location for log files, storage folder is configured in bootstrap/paths.php
'storage' => __DIR__.'/../app/storage',
Also be sure that this folder is writable by the web server.
The problem was permissions.
User permissions for the www-var user in the ../app/storage
And MySQL settings: Creating a user corresponding to what is set in the app/config/database.php
'mysql' => array(
'driver' => 'mysql',
'host' => 'your host',
'database' => 'your db',
'username' => 'your user',
'password' => 'your pass',
),

Categories