You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EC2实例PHP程序调用SecretsManager遇400权限错误求助

问题

我在EC2实例上编写了一个独立PHP程序,用于从SecretsManager读取密钥(EC2实例与密钥处于同一区域),AWS SDK PHAR包与程序在同一目录。程序代码如下:

<?php

 require 'aws.phar'; // Include the AWS SDK for PHP

 use Aws\SecretsManager\SecretsManagerClient;
 use Aws\Sts\StsClient;
 use Aws\Exception\AwsException;
 $client = new SecretsManagerClient([
'version' => 'latest',
'region' => 'us-west-1',
]);

$result = $client->getSecretValue([
'SecretId' => 'prod/vserver/api-keys',
]);
$secretString = $result['SecretString'];

我希望EC2实例无需提供显式AWS凭证即可获取密钥,已完成以下配置:

  1. 创建了IAM策略:
{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "AllowReadSecrets",
        "Effect": "Allow",
        "Action": "secretsmanager:GetSecretValue",
        "Resource": "arn:aws:secretsmanager:us-west-1:ACCOUNTID:secret:prod/vserver/api-keys"
    }
  ]
}
  1. 创建名为EC2_ACCESS_SECRETSMANAGER的IAM角色,将上述策略附加到该角色,并为运行PHP程序的EC2实例关联此角色。

但运行程序时出现400权限拒绝错误:

Next Aws\SecretsManager\Exception\SecretsManagerException: Error executing "GetSecretValue" on "https://secretsmanager.us-west-1.amazonaws.com"; AWS HTTP error: Client error: POST https://secretsmanager.us-west-1.amazonaws.com resulted in a 400 Bad Request response:
{"__type":"AccessDeniedException","Message":"User: arn:aws:sts::<AWS_ACCOUNT_ID>:assumed-role/EC2_ACCESS_SECRETSMANAGER/i-08 (truncated...)
AccessDeniedException (client): User: arn:aws:sts::<AWS_ACCOUNT_ID>:assumed-role/EC2_ACCESS_SECRETSMANAGER/ is not authorized to perform: secretsmanager:GetSecretValue on resource: prod/vserver/api-keys because no identity-based policy allows the secretsmanager:GetSecretValue action - {"__type":"AccessDeniedException","Message":"User: arn:aws:sts::<AWS_ACCOUNT_ID>:assumed-role/EC2_ACCESS_SECRETSMANAGER/ is not authorized to perform: secretsmanager:GetSecretValue on resource: prod/vserver/api-keys because no identity-based policy allows the secretsmanager:GetSecretValue action"} in phar:///var/www/html/aws.phar/Aws/WrappedHttpHandler.php:195

注:<AWS_ACCOUNT_ID>为占位符。

解决方案

1. 替换IAM策略中的账户ID占位符

策略中Resource字段的ACCOUNTID是占位符,必须替换为你的实际AWS账户ID。AWS无法识别占位符,会导致策略无法匹配目标资源,触发权限拒绝。

修正后的策略示例:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "AllowReadSecrets",
        "Effect": "Allow",
        "Action": "secretsmanager:GetSecretValue",
        "Resource": "arn:aws:secretsmanager:us-west-1:123456789012:secret:prod/vserver/api-keys"
    }
  ]
}

(将123456789012替换为你的实际账户ID)

2. 匹配Secrets Manager密钥的完整ARN

AWS Secrets Manager创建密钥时,会自动为ARN追加随机后缀(例如prod/vserver/api-keys-abc123),如果你的密钥实际ARN包含该后缀,策略的Resource字段必须完全匹配完整ARN,不能只写前缀prod/vserver/api-keys。

你可以在Secrets Manager控制台找到目标密钥的完整ARN,替换到策略的Resource字段中。

3. 验证EC2实例的角色关联状态

  • 登录EC2实例,执行以下命令确认实例已获取目标角色:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

如果返回EC2_ACCESS_SECRETSMANAGER,说明角色关联正常;如果返回空或其他角色名,需要重新为EC2实例关联该角色。

  • 进一步验证权限:
    先获取实例的临时凭证:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2_ACCESS_SECRETSMANAGER

用返回的AccessKeyId、SecretAccessKey和Token执行AWS CLI命令测试:

aws secretsmanager get-secret-value --secret-id prod/vserver/api-keys --region us-west-1 --access-key-id <AccessKeyId> --secret-access-key <SecretAccessKey> --session-token <Token>

如果CLI也报错,说明权限配置存在问题;如果CLI能成功获取密钥,再排查PHP程序的逻辑。

4. 确保PHP SDK使用实例角色凭证

AWS SDK for PHP默认会优先读取环境变量中的凭证(如AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY),如果实例上存在这些环境变量,会导致SDK忽略EC2角色凭证。

可以在程序中强制指定使用实例元数据凭证提供者:

$client = new SecretsManagerClient([
    'version' => 'latest',
    'region' => 'us-west-1',
    'credentials' => new Aws\Credentials\InstanceProfileCredentials()
]);

内容的提问来源于stack exchange,提问作者Rahul Saini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:07:11