1

我正在使用 Amazon ElasticSearch 服务,当我尝试创建 SignatureV4 请求时,它对于搜索操作(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"}
4

1 回答 1

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 并使用基于 IAM 的身份验证在 Amazon 云中的 Elasticsearch 托管服务的任何人有益。

于 2017-05-23T10:54:02.530 回答