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

ESデータをIAM Roleで取得する方法です。
ESのポリシーがガチガチじゃないかたはこちら=>[AWS ElasticSearch ServiceのデータをPHPで取得する](https://qiita.com/bboobbaa/items/d9e0854f0278064ae181)

# はじめに

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

# AWS側の設定

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

```json:
{
  "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、接続に必要なものをインストールします。

```json: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 検索リクエストへの署名](https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/service_es-data-plane.html)

# aws-sdk-php-laravelの設定

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

参考サイト=>[GitHub aws/aws-sdk-php-laravel](https://github.com/aws/aws-sdk-php-laravel)

```php: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にて設定した環境変数を読み込むように上書きします。

```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から勉強してみた](https://qiita.com/toshihirock/items/e49b66f8685a8510bd76)


```php: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編]](https://www.hands-lab.com/tech/entry/1027.html)