0

I get the following error when trying to create an SNSClient object.

InstanceProfileCredentialsException in InstanceMetadataClient.php line 85: 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. (Client error response
[status code] 404
[reason phrase] Not Found
[url] http://169.254.169.254/latest/meta-data/iam/security-credentials/)

I don't understand why I have this error when I have my aws.php in the config folder of my laravel setup. Here the access key and secret key are stored.

I don't really like this since this causes my credentials to be stored in the folder setup where other's may SFTP into.

What I also have is the aws credentials and config files in my server root folder, in a path like this: ~/.aws/ but for some reason the application is not happy.

Here's what my code looks like:

public function about(){

    // Instantiate a client with the credentials from the project1 profile
    $snsClient = SnsClient::factory(array(
            'profile' => 'default',
            'region'  => 'us-west-2',
        ));

    // Get the application's endpoints

    $iOS_AppArn = "arn:aws:sns:us-west-2:235418406768:app/APNS_SANDBOX/ClashTarget";

    $iOS_model = $snsClient->listEndpointsByPlatformApplication(array('PlatformApplicationArn' => $iOS_AppArn));
}

Note that I am using the default profile which should take the credentials from the root aws directory where the config and credential files are stored.

For now, as a temporary solution I did this: http://blog.ianholden.com/aws-s3-with-php-on-apache/ which makes everything work but I'm not happy having my credential keys living in the application code. It doesn't feel right.

Can someone guide me in getting this error resolved please?

Update 1: Comment: What is the content of config at ~/.aws/ This is the content of the config file in the ~/.aws/ folder

[default]
output = json
region = us-west-2
Pavan
  • 17,840
  • 8
  • 59
  • 100
  • pls show the content of config at ~/.aws/ – Evgeniy Kuzmin Jun 03 '15 at 17:49
  • What do `print_r(getenv('HOME'));` and `$func = \Aws\Credentials\CredentialProvider::ini(); print_r($func());` show? – patricus Jun 03 '15 at 19:40
  • @EvgeniyKuzmin Please see **update 1** in my post. Incase you also wanted to know the content of the credentials file at the same folder, here it is: `aws_access_key_id = AKIAKDH4JFYI3IRK7SAQ` on line 1 and `aws_secret_access_key = 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` on line 2 obviously with a few characters changed. – Pavan Jun 03 '15 at 20:12
  • @patricus I am getting this error: FatalErrorException in PagesController.php line 56: Class 'App\Http\Controllers\Aws\Credentials\CredentialProvider' not found I tried using the Aws\Common\Credentials\Credentials instead but that also causes a similar problem. – Pavan Jun 03 '15 at 20:36
  • @Pavan make sure you're including the starting backslash: i.e. `\Aws\Credentials\CredentialProvider::ini()`, not just `Aws\Credentials\CredentialProvider::ini()`. – patricus Jun 03 '15 at 20:37
  • Yes, I did do just that. I accidentally omitted when pasting the comment – Pavan Jun 03 '15 at 22:03

3 Answers3

5

Your ~/.aws/credentials file should look like this:

[default]
aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY

[project1]
aws_access_key_id = ANOTHER_AWS_ACCESS_KEY_ID
aws_secret_access_key = ANOTHER_AWS_SECRET_ACCESS_KEY

The following function is used by the library to determine the directory in which to look for the .aws/credentials file:

private static function getHomeDir()
{
    // On Linux/Unix-like systems, use the HOME environment variable
    if ($homeDir = getenv('HOME')) {
        return $homeDir;
    }
    // Get the HOMEDRIVE and HOMEPATH values for Windows hosts
    $homeDrive = getenv('HOMEDRIVE');
    $homePath = getenv('HOMEPATH');
    return ($homeDrive && $homePath) ? $homeDrive . $homePath : null;
}

As you can see, if the HOME or the HOMEDRIVE and HOMEPATH environment variables are not set, the library will not be able to find your credentials file.

In addition to being able to find the file, it also needs to be readable by PHP, and in an INI format (as described above).

Edit

From comments, it sounds like the HOME environment variable is not set. Because of this, the library cannot find your credentials file. There are a few options for where to go from here.

Option 1:

Fix your server so that the HOME environment variable is set correctly. You will need to do some research on the best way to do this, as the solution may be highly dependent on server/apache/php configurations...

Option 2:

Since you're using Laravel 5, you can add your credentials to your .env file, and then access them in the code. So, for example, add the following two lines to the end of your .env file:

AWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY

Now, in your code, you can do:

public function about() {
    // add "use Aws\Credentials\Credentials;" at the top of your file

    // the env() method reads the values from the .env file. ideally you should never
    // use the env() method outside of a config file, though, so I'd suggest adding
    // a new config file that uses the env statements and using the config here.
    $credentials = new Credentials(env('AWS_ACCESS_KEY_ID'), env('AWS_SECRET_ACCESS_KEY'));

    // if using the 'credentials' key, do not use the 'profile' key
    $snsClient = SnsClient::factory(array(
        'region'  => 'us-west-2',
        'credentials' => $credentials
    ));
}

Option 3:

Call the CredentialProvider::ini() method yourself and pass in the profile and full path to your ini file. This will bypass the need for the library to try and determine the home directory.

public function about() {
    // add "use Aws\Credentials\CredentialProvider;" at the top of your file

    // the first parameter is the profile, the second parameter is the full path to
    // your credentials file. You may want to add this to your .env file, and
    // access using env()/config() instead of hardcoding here, though.
    $credentials = CredentialProvider::ini('default', '/root/.aws/credentials');

    // if using the 'credentials' key, do not use the 'profile' key
    $snsClient = SnsClient::factory(array(
        'region'  => 'us-west-2',
        'credentials' => $credentials
    ));
}
patricus
  • 59,488
  • 15
  • 143
  • 145
  • Hey patricus, 1) my file does look like that, the first three lines only. 2) the `getenv` function returns a `strlength` of `0`. And, 3) As I mentioned before in a previous comment, your block of code regarding the credential provider returns a `FatalErrorException in PagesController.php line 21: Class 'Aws\Credentials\CredentialProvider' not found in PagesController.php line 21` error. – Pavan Jun 03 '15 at 22:02
  • @Pavan If `getenv('HOME')` is empty (for linux) and both `getenv('HOMEDRIVE')` and `getenv('HOMEDRIVE')` are empty (for windows), then that is your issue. The library one set of these values to find the credentials file. – patricus Jun 04 '15 at 01:59
  • I'm using an amazon linux ami instance, NS `getenv('HOME')` is empty. How should I proceed? – Pavan Jun 04 '15 at 02:34
  • @Pavan Are you using Laravel 4 or 5? – patricus Jun 04 '15 at 04:25
  • I'm using Laravel 5 buddy. – Pavan Jun 04 '15 at 21:27
0

I can't see exactly reason why you are getting the error, but

I don't really like this since this causes my credentials to be stored in the folder setup where other's may SFTP into.

I suppose you certainly need to setup IAM Role at AWS console to allow connect to SNS from your EC2 instance(s). In this way you won't need to provide any credentials

Evgeniy Kuzmin
  • 2,384
  • 1
  • 19
  • 24
  • I have setup an IAM Role, called administrator who only has access to SNSFullAccess policy. And it's those credentials that i'm writing in one of the files which is part of the sftp folder. I'd rather the credentials be read from the ~/.aws/ directory instead. – Pavan Jun 03 '15 at 20:33
0

From @Pavan's comment on his question in which he shows the contents of the credentials file in ~/.aws, it seems that there are 2 files there. I only have one file

$ cat ~/.aws/credentials
[default]
aws_access_key_id = blablabla
aws_secret_access_key = blablabla
region = us-west-2
Shadi
  • 9,742
  • 4
  • 43
  • 65