使用Guzzle 3调用AWS Secrets Manager API报错400及签名异常求助
问题排查修复点
- 时间戳一致性问题:你代码中多处调用
new DateTime('UTC')生成时间,不同位置生成的时间可能存在秒级甚至分钟级差异,AWS签名要求所有参与签名计算、请求头传递的时间必须完全一致。请在代码最开始生成一次全局UTC时间,所有位置复用该值即可。 - Host头格式错误:构造规范请求的
canonical_headers时,Host头不需要带https://前缀,也不能有尾部空格,正确格式为host:secretsmanager.{你的区域ID}.amazonaws.com。 - 规范请求构造错误:
- 规范请求中的URI路径
/GetSecretValue不能带前后多余空格 - 规范请求必须包含请求Body的SHA256哈希值,你当前构造时遗漏了该字段
- 你在
Authorization头的SignedHeaders中声明了content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target,但构造canonical_headers时未加入x-amz-content-sha256、x-amz-target两个头,签名参与的头和声明的头不匹配直接导致签名校验失败。
- 规范请求中的URI路径
- Guzzle 3 请求参数格式错误:Guzzle 3的
post方法第二个参数是配置数组,请求头必须放在headers子数组下,你直接将头键值放在第二层,Guzzle不会将其识别为请求头,导致实际发出的请求和签名用的参数不一致。 - 硬编码值错误:
Authorization头中的Credential你硬编码了ACCESSKEYID和固定日期20210526,需要替换成代码中实际的$access_key和动态生成的$amzdate2。
核心修复代码示例
try { // 只生成一次时间,全局复用 $utcNow = new DateTime('UTC'); $amzdate = $utcNow->format('Ymd\THis\Z'); $amzdate2 = $utcNow->format('Ymd'); $secretKey = "你的AWS密钥"; $access_key = "你的AWS访问键"; $region = REGIONID; $service = 'secretsmanager'; $alg = 'sha256'; $algorithm = 'AWS4-HMAC-SHA256'; // 补全所有参与签名的头 $signed_headers = 'content-type;host;x-amz-date;x-amz-target'; $payload = json_encode(array('SecretId' => '你的SecretID')); $payloadHash = hash('sha256', $payload); // 修正host头,补全所有需要签名的头 $canonical_headers = "content-type:application/x-amz-json-1.1\n" . "host:secretsmanager.".$region.".amazonaws.com\n" . "x-amz-date:".$amzdate."\n" . "x-amz-target:secretsmanager.GetSecretValue\n"; // 修正规范请求,去掉路径空格,补全payload哈希 $canonical_request = "POST\n" . "/GetSecretValue\n" . "\n" . $canonical_headers . "\n" . $signed_headers . "\n" . $payloadHash; $credential_scope = $amzdate2 . '/' . $region . '/' . $service . '/' . 'aws4_request'; $string_to_sign = "AWS4-HMAC-SHA256\n" . $amzdate . "\n" . $credential_scope . "\n" . hash('sha256', $canonical_request); // 签名计算部分保持不变 $kSecret = 'AWS4' . $secretKey; $kDate = hash_hmac($alg, $amzdate2, $kSecret, true); $kRegion = hash_hmac($alg, $region, $kDate, true); $kService = hash_hmac($alg, $service, $kRegion, true); $kSigning = hash_hmac($alg, 'aws4_request', $kService, true); $signature = hash_hmac('sha256', $string_to_sign, $kSigning); $client = new Client(); $url = 'https://secretsmanager.' . $region . '.amazonaws.com/GetSecretValue'; // 修正Guzzle3头的传参格式 $request = $client->post( $url, array( 'headers' => array( 'Content-Type' => 'application/x-amz-json-1.1', 'X-Amz-Target' => 'secretsmanager.GetSecretValue', 'X-Amz-Date' => $amzdate, 'Authorization' => sprintf( 'AWS4-HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s', $access_key, $credential_scope, $signed_headers, $signature ) ) ), $payload ); $response = json_decode($client->send($request)->getBody(true)); var_dump($response); } catch(Guzzle\Http\Exception\ClientErrorResponseException $e){ echo '<pre>',var_dump($e->getResponse()->getBody()),'</pre>'; }
内容的提问来源于stack exchange,提问作者Hanane
相关产品推荐
相关产品推荐

