我如何获得AWS PHP SDK来查找存储在Elastic Beanstalk环境变量中的凭证?

问题描述 投票:1回答:1

我正在使用PHP在AWS Elastic Beanstalk上运行Web应用程序。

该应用程序使用RDS MySQL数据库。我想通过AWS Secrets Manager存储数据库凭证。

我成功创建了秘密。

通过作曲家,我安装了AWS PHP SDK,版本3.129。我运行了compatibility.test php文件来验证我的开发环境。一切都是绿色的(除了出于性能原因不使用Xdebug的警告)。

[使用AWS文档,我编写了一个PHP类来获取秘密值。我为该课程写了单元测试。单元测试通过了,我能够使用RDS的用户名,密码等显示秘密值。

为了提供本地开发环境的凭据,我使用了存储在.aws目录中的凭据文件。在此文件中,我存储了:

  • aws_access_key_id
  • aws_secret_access_key

我在本地apache网络服务器上运行了我的应用程序,它能够从AWS Secrets Manager成功检索RDS凭据,并对RDS数据库进行MySQL调用。

我的最后一步是通过我的Elastic Beanstalk平台在AWS中运行该应用程序(该平台已经运行了几个月,并且具有我想停止使用的硬编码RDS凭证)。

我看了解释"Credentials for the AWS SDK for PHP Version 3的AWS文档。该文档描述了“默认凭证提供者链”。

我尝试了(未成功)使用链中的第一个链接,即环境变量,紧跟标题为“使用环境变量中的凭据”的this AWS document。该文件指出:

如果您将应用程序托管在AWS Elastic Beanstalk上,则可以通过AWS Elastic Beanstalk控制台设置AWS_ACCESS_KEY_ID和AWS_SECRET_KEY环境变量,以便SDK可以自动使用这些凭据。

我通过AWS控制台使用了这些值作为变量:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

[在测试期间,我尝试了两个访问密钥,并且我知道它们可以工作,因为我将它们用于其他目的,并且IAM控制台显示了这两个的最近使用。

[运行测试时,我总是在AWS PHP SDK代码中遇到相同的异常,该异常报告“无法从/.aws/credentials读取凭据”。

这向我暗示:

  1. PHP SDK代码不在寻找我的环境变量
  2. 它试图找到他们,但找不到
  3. 它找到了他们,但无法使用它们

[当我遇到异常时,我会收到“ Whoops”输出,其中显示了AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY环境变量以及它们的值,与输入时完全相同。

PHP SDK代码是正确的,因为我没有将其上传到Elastic Beanstalk,所以它找不到我的凭据文件。这种方式对我来说在Elastic Beanstalk中是没有意义的,尽管它对于我的本地环境也很好。

这里是异常回溯中的最后几个调用:

Aws \ Exception \ CredentialsException…/ vendor / aws / aws-sdk-php / src / Credentials / CredentialProvider.php69121Aws \ Credentials \ CredentialProvider拒绝…/ vendor / aws / aws-sdk-php / src / Credentials / CredentialProvider.php42420Aws \ Credentials \ CredentialProvider Aws \ Credentials {关闭}…/ vendor / aws / aws-sdk-php / src / Middleware.php12119Aws \ Middleware Aws {closure}…/ vendor / aws / aws-sdk-php / src / RetryMiddleware.php26918岁Aws \ RetryMiddleware __调用…/ vendor / aws / aws-sdk-php / src / Middleware.php20617Aws \ Middleware Aws {closure}…/ vendor / aws / aws-sdk-php / src / StreamRequestPayloadMiddleware.php83

这是我在“凭据提供拒绝”中输入的代码:

            if (!is_readable($filename)) {
            return self::reject("Cannot read credentials from $filename");
        }

这是我为获取机密而编写的代码(带有一些无关的调试语句,稍后将删除):

    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;
}

从我的调试看来,SDK只是忽略了凭证文件以外的任何凭证提供方法。我尝试过:

  1. 运行本地Web服务器时在本地计算机上设置本地环境变量。
  2. 将我的SDK客户端数组设置为仅查看env()方法。
  3. 对我的凭据进行硬编码。

设置我的信誉的这些方法中没有一个有效。

我还尝试使用旧版本的SDK,以查看是否最近引入了错误,最早可以追溯到3.76.0。没什么区别。

这是修改后的代码,显示上面注释为2的尝试和上面尝试3的尝试:

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;
}

我还尝试了通过默认链获取凭据的第二种方法:承担IAM角色。我尝试遵循文档here,但坦率地发现它令人困惑。在我的Elastic Beanstalk Security配置中,我注意到了两个IAM角色:

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

我为以下两个角色分配了以下策略:

  1. SecretsManagerReadWrite
  2. IAMFullAccess(因为当我分配上一个策略时,也有一条注释也要分配此策略)

分配这些IAM策略不能解决问题。

我的首选是通过Elastic Beanstalk环境变量解决此问题,因为它看起来非常简单,并且AWS文档明确指出它应该可以工作。另外,如果不需要大量脚本,则希望通过IAM策略解决它。

我该如何解决这个问题?

php amazon-web-services amazon-ec2 amazon-elastic-beanstalk
1个回答
0
投票

(代表问题作者发布的解决方案,以便将其从问题中移出)

在我的客户端SecretsManagerClient数组中,包含以下行:

            'profile' => 'default',

通过单步执行SDK代码,我观察到该行的存在被解释为“查找凭证文件并跳过默认的凭证链”。

我删除了这一行,然后SDK处理了在我的环境变量中设置的凭据。

© www.soinside.com 2019 - 2024. All rights reserved.