简体   繁体   中英

How do I get the AWS PHP SDK to find the credentials I stored in Elastic Beanstalk environment variables?

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:

  1. The PHP SDK code is not looking for my environment variables
  2. It tried to find them but could not
  3. 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:

  1. Setting local environment variables on my local machine when running the local webserver.
  2. Setting my SDK client array to only look at the env() method.
  3. 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:

  1. aws-elasticbeanstalk-ec2-role
  2. aws-elasticbeanstalk-service-role

I assigned the following policies to both roles:

  1. SecretsManagerReadWrite
  2. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM