PHP
AWS
laravel
Elasticsearch
ElasticsearchService

IAM Roleを使ってAWS ElasticSearch ServiceのデータをLaravelで取得する

ESデータをIAM Roleで取得する方法です。
ESのポリシーがガチガチじゃないかたはこちら=>AWS ElasticSearch ServiceのデータをPHPで取得する

はじめに

PHPが稼働しているサーバーに以下環境変数を設定して下さい。
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION

AWS側の設定

Amazon Elasticsearch Serviceポリシー例
上記で設定したユーザーでみGETで取得が出来るように設定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::000000000000:user/xxx"
      },
      "Action": "es:ESHttpGet",
      "Resource": "arn:aws:es:ap-northeast-1:000000000000:domain/xxx/*"
    }
  ]
}

Composerでインストール

AWS-SDK、ClientBuilder、接続に必要なものをインストールします。

composer.json
"require": {
  "aws/aws-sdk-php-laravel": "~3.0",
  "elasticsearch/elasticsearch": "~6.0",
  "guzzlehttp/guzzle": "^6.0",
  "psr/http-message": "^1.0"
}

$ composer update

参考サイト=>Amazon Elasticsearch Service 検索リクエストへの署名

aws-sdk-php-laravelの設定

READMEを参考に先ほど設定した環境変数を読み込むためにconfig/app.phpにprovidersaliasesを設定します。

参考サイト=>GitHub aws/aws-sdk-php-laravel

config/app.php
'providers' => array(
    // ~
    Aws\Laravel\AwsServiceProvider::class,
)
// ~
'aliases' => array(
    // ~
    'AWS' => Aws\Laravel\AwsFacade::class,
)

以下を実行するとconfig/aws.phpが生成されます。

$ php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider"

うまくできない人は以下のコマンドを先に入力すると解決するかもしれません。

$ php artisan config:clear

生成されたconfig/aws.phpにて設定した環境変数を読み込むように上書きします。

config/aws.php
return [
    'credentials' => [
        'key'    => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
    ],
    'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
];

PHP側から読み込み

リクエスト署名を挿入してClientBuilderに接続します。
途中でPromise rejectエラーなど出た場合はコメントアウト部分を表示してみるとエラー詳細が出ると思います。

Promiseって何という方はこちらを参考にすると良いかもしれません。
参考サイト=>Promiseについて0から勉強してみた

xxx.php
use AWS;
use Aws\Credentials\CredentialProvider;
use Aws\Signature\SignatureV4;
use Elasticsearch\ClientBuilder;
use GuzzleHttp\Ring\Future\CompletedFutureArray;
use GuzzleHttp\Psr7\Request as psr7Request;
use GuzzleHttp\Psr7\Uri;
//use Psr\Http\Message\ResponseInterface;

$psr7Handler = Aws\default_http_handler();

$signer = new SignatureV4('es', env('AWS_DEFAULT_REGION'));

$credentialProvider = CredentialProvider::defaultProvider();

$handler = function (array $request) use ($psr7Handler, $signer, $credentialProvider)
{
    $request['headers']['Host'][0] = parse_url($request['headers']['Host'][0], PHP_URL_HOST);

    $psr7Request = new psr7Request(
        $request['http_method'],
        (new Uri($request['uri']))
            ->withScheme($request['scheme'])
            ->withHost($request['headers']['Host'][0]),
        $request['headers'],
        $request['body']
    );

    $signedRequest = $signer->signRequest(
        $psr7Request,
        call_user_func($credentialProvider)->wait()
    );

    $response = $psr7Handler($signedRequest)->wait();
    /*$response = $psr7Handler($signedRequest)->then(
        function(Psr\Http\Message\ResponseInterface $r) {
            return $r;
        }, function($error) {
            return $error['response'];
        }
    )->wait();*/

    return new CompletedFutureArray([
        'status' => $response->getStatusCode(),
        'headers' => $response->getHeaders(),
        'body' => $response->getBody()->detach(),
        'transfer_stats' => ['total_time' => 0],
        'effective_url' => (string) $psr7Request->getUri(),
    ]);
};

$hosts = [
    'https://xxx.ap-northeast-1.es.amazonaws.com:443'
];

$client = ClientBuilder::create()->setHandler($handler)->setHosts($hosts)->build();

$params = [
    'index' => '*'
];

$response = $client->search($params);

$responseにデータ返ってきていると思います。

参考サイト=>AWS ElasticSearch Service の認証にIAM Roleを使う [PHP編]