我正在使用PHP在AWS Elastic Beanstalk上运行Web应用程序。
该应用程序使用RDS MySQL数据库。我想通过AWS Secrets Manager存储数据库凭证。
我成功创建了秘密。
通过作曲家,我安装了AWS PHP SDK,版本3.129。我运行了compatibility.test php文件来验证我的开发环境。一切都是绿色的(除了出于性能原因不使用Xdebug的警告)。
[使用AWS文档,我编写了一个PHP类来获取秘密值。我为该课程写了单元测试。单元测试通过了,我能够使用RDS的用户名,密码等显示秘密值。
为了提供本地开发环境的凭据,我使用了存储在.aws目录中的凭据文件。在此文件中,我存储了:
我在本地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控制台使用了这些值作为变量:
[在测试期间,我尝试了两个访问密钥,并且我知道它们可以工作,因为我将它们用于其他目的,并且IAM控制台显示了这两个的最近使用。
[运行测试时,我总是在AWS PHP SDK代码中遇到相同的异常,该异常报告“无法从/.aws/credentials读取凭据”。
这向我暗示:
[当我遇到异常时,我会收到“ 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只是忽略了凭证文件以外的任何凭证提供方法。我尝试过:
设置我的信誉的这些方法中没有一个有效。
我还尝试使用旧版本的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角色:
我为以下两个角色分配了以下策略:
分配这些IAM策略不能解决问题。
我的首选是通过Elastic Beanstalk环境变量解决此问题,因为它看起来非常简单,并且AWS文档明确指出它应该可以工作。另外,如果不需要大量脚本,则希望通过IAM策略解决它。
我该如何解决这个问题?
(代表问题作者发布的解决方案,以便将其从问题中移出)。
在我的客户端SecretsManagerClient数组中,包含以下行:
'profile' => 'default',
通过单步执行SDK代码,我观察到该行的存在被解释为“查找凭证文件并跳过默认的凭证链”。
我删除了这一行,然后SDK处理了在我的环境变量中设置的凭据。