我正在使用Amazon ElasticSearch Service,当我尝试创建SignatureV4 Request时,它可以正常运行搜索操作(GET请求)。但是,当我尝试执行某些操作(如创建索引(使用PUT请求))时,它将通过签名不匹配错误。
我正在使用Amazon SDK版本2 SignatureV4库来签署请求。还创建了一个自定义Elasticsearch处理程序,以将令牌添加到请求中。
在Amazon SDK php V2中是否有任何人对SignatureV4库存在此类问题。
{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been\n'PUT\n/test_index_2\n\nhost:search-test-gps2gj4zx654muo6a5m3vxm3cy.eu-west-1.es.amazonaws.com\nx-amz-date:XXXXXXXXXXXX\n\nhost;x-amz-date\n271d5ef919251148dc0b5b3f3968c3debc911a41b60ef4e92c55b98057d6cdd4'\n\nThe String-to-Sign should have been\n'AWS4-HMAC-SHA256\XXXXXXXXXXXX\n20170511/eu-west-1/es/aws4_request\n0bd34812e0727fba7c54068b0ae1114db235cfc2f97059b88be43e8b264e1d57'\n"}
答案 0 :(得分:0)
此调整仅对仍在使用Amazon SDK PHP版本2的用户所必需。在版本3中,默认情况下支持。
对于已签名的请求,我通过添加用于签署请求的中间件来更新当前的elsticsearch客户端处理程序。
$elasticConfig = Configure::read('ElasticSearch');
$middleware = new AwsSignatureMiddleware();
$defaultHandler = \Elasticsearch\ClientBuilder::defaultHandler();
$awsHandler = $middleware($defaultHandler);
$clientBuilder = \Elasticsearch\ClientBuilder::create();
$clientBuilder->setHandler($awsHandler)
->setHosts([$elasticConfig['host'].':'.$elasticConfig['port']]);
$client = $clientBuilder->build();
我为此目的使用了以下库
use Aws\Common\Credentials\CredentialsInterface;
use Aws\Common\Signature\SignatureInterface;
use Guzzle\Http\Message\Request;
class AwsSignatureMiddleware
{
/**
* @var \Aws\Credentials\CredentialsInterface
*/
protected $credentials;
/**
* @var \Aws\Signature\SignatureInterface
*/
protected $signature;
/**
* @param CredentialsInterface $credentials
* @param SignatureInterface $signature
*/
public function __construct()
{
$amazonConf = Configure::read('AmazonSDK');
$this->credentials = new \Aws\Common\Credentials\Credentials($amazonConf['key'], $amazonConf['secret']);
$this->signature = new \Aws\Common\Signature\SignatureV4('es', 'eu-west-1');
}
/**
* @param $handler
* @return callable
*/
public function __invoke($handler)
{
return function ($request) use ($handler) {
$headers = $request['headers'];
if ($headers['host']) {
if (is_array($headers['host'])) {
$headers['host'] = array_map([$this, 'removePort'], $headers['host']);
} else {
$headers['host'] = $this->removePort($headers['host']);
}
}
if (!empty($request['body'])) {
$headers['x-amz-content-sha256'] = hash('sha256', $request['body']);
}
$psrRequest = new Request($request['http_method'], $request['uri'], $headers);
$this->signature->signRequest($psrRequest, $this->credentials);
$headerObj = $psrRequest->getHeaders();
$allHeaders = $headerObj->getAll();
$signedHeaders = array();
foreach ($allHeaders as $header => $allHeader) {
$signedHeaders[$header] = $allHeader->toArray();
}
$request['headers'] = array_merge($signedHeaders, $request['headers']);
return $handler($request);
};
}
protected function removePort($host)
{
return parse_url($host)['host'];
}
}
我为此目的调整的确切行是
if (!empty($request['body'])) {
$headers['x-amz-content-sha256'] = hash('sha256', $request['body']);
}
对于PUT和POST请求,有效负载哈希是错误的,因为我在生成有效负载时没有考虑请求体。
希望此代码对于使用Amazon SDK PHP版本2并在Amazon云中使用基于IAM的身份验证进行Elasticsearch托管服务的任何人都有益。