1

我正在使用Amazon ElasticSearch服務,當我嘗試創建SignatureV4請求時,它對於搜索操作(GET請求)正常工作。但是當我試圖做一些像創建索引(使用PUT請求)的操作時,它會通過簽名不匹配錯誤。亞馬遜ElasticSearch服務簽名不匹配PUT請求 - 亞馬遜SDK php V2

我正在使用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

http://docs.aws.amazon.com/general/latest/gr/signature-v4-troubleshooting.html –

+0

是@VladHolubiev我嘗試了與他們記錄的相同方式,並且它對GET操作起作用,例如(search,find物品等)。但不適用於PUT操作。 – vims

+0

如果它適用於一種而非另一種,那麼請求中的細微差異會使邏輯無效。該錯誤消息爲您提供了一些有價值的麻煩搜索信息,包括規範請求(以sha256hex有效負載哈希結束)和字符到符號(以標準請求的sha256hex哈希結束)。找到簽名過程中產生錯誤結果的步驟,並解決在該步驟發生的問題。它只能在那裏,而不是在以後,因爲在任何步驟的錯誤結果總是會級聯。 –

回答

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託管服務身份驗證的用戶都有益。