2019.01.09

AWS AmplifyによるIAM認証時に、ローカルのElasticsearchへアクセスする際のCORS設定

概要

AWS Amplifyを使用してIAM認証されている状態で、ローカル開発環境状のElasticsearchへ接続しようとした際、CORSエラーとなりました。
原因は、IAM認証されている状態で、AWS Amplifyでは認証用のいくつかのHTTPヘッダを付与したアクセスを行なっていたため、Elasticsearch側のCORS設定時に、それらのヘッダの許可が必要でした。
本記事では、エラーが発生した状況と解決方法を記載しています。

構築した環境

AWS上の環境

AWSのElasticsearch Serviceへ接続するWebアプリ(Vue.js)を作りました。
ElasticsearchクラスタへはIAM認証によるアクセス制限をかけており、ユーザー認証はCognitoを使用しています。

ローカル開発環境

しかし、ローカル開発時には、普通はAWSではなくローカルのElasticsearchへ接続したいはずです。
そこで、WebアプリコンテナとElasticsearchのコンテナが起動して通信できるようなdocker-composeを構築しました。
あとはアプリコンテナからElasticsearchコンテナへ接続すればOK...とはならずCORSで弾かれてしまいました...orz

構築概要

ローカル開発用のdocker-composeはこんな感じです。
Vue.js(Nuxt)のWebアプリコンテナからElasticsearchのコンテナへアクセスできるよう、"container_name"を指定し、同じネットワーク内に配置しています。
ちなみに、elasticsearch.ymlを上書きするよう、volumeマウントしています。

docker-compose.yml

version: '3'
services:
  app:
    build: .
    image: app:latest
    depends_on:
      - elasticsearch
    environment:
      HOST: 0.0.0.0
    ports:
      - 80:80
      - 3500:3000
      - 8581:8080
    volumes:
      - ./nuxt:/nuxt
    working_dir: /nuxt
    command: sh -c "yarn && yarn dev"
    networks:
      - default

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
    container_name: elasticsearch
    environment:
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ./elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
      - ./elasticsearch/esdata:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - default

CORSエラーとElasticsearchの設定追加

Elasticsearchにアクセスすると

AWS Amplifyを認証に使用したアプリケーション(Vue.js)から、ローカルに手動構築した Elasticsearch へアクセスする際に、CORSでエラーになってしまいます。

elasticsearch cors error 1

Elasticseachの設定ファイル(elasticsearch.yml)に、CORS関連設定の追記が必要そうです。

CORSの許可

Cross-Originを許可するよう、以下の設定を追記しました。

elasticsearch.yml

http.cors.enabled: true
http.cors.allow-origin: /https?:\\/\\/localhost(:[0-9]+)?/

再度トライ

まだエラーが出ます。 エラーの内容が少し変わってます。

elasticsearch cors error 2

error

Request header field X-Amz-Date is not allowed by Access-Control-Allow-Headers in preflight response.

X-Amz-Date というヘッダーがAccess-Control-Allow-Headersで許可されていない、とのこと。
X-Amz-Date などのヘッダーは、AWSv4署名されているリクエストに付与されるものです。

アクセス時のリクエストヘッダー

Elasticsearchへのアクセスは、NodejsのSDKを以下のような感じで使っています。

サンプルコード(nodejs)

import elasticsearch from "elasticsearch";

const client = elasticsearch.Client({
  host: process.env.Elasticsearch.endpoint,
  connectionClass: require('http-aws-es'),
  log: 'trace'
})

export default {
  client: client
}

const res = await libEs.client.search({
  index: 'app',
  body: body
})

http-aws-es というモジュールを使用して接続しています。
これによって、Elasticsearchへアクセスする際に、ブラウザ側で保持している認証情報(Credentials)によって署名したリクエストが送信されます。

CORSではヘッダーの許可も必要

AWS Amplify でCognito認証を通した後のv4署名リクエストでは、以下のヘッダーが付与されるようです。

  • x-amz-security-token
  • X-Amz-Date
  • Authorization

elasticsearch.ymlには、以下の行も追記します。

elasticsearch.yml (追加)

http.cors.allow-headers: X-Requested-With, Content-Type, Content-Length, x-amz-security-token, X-Amz-Date, Authorization

設定ファイルまとめ

まとめると、以下の設定でローカル環境にてアクセスできるようになりました。
(デフォルトのelasticsearch.ymlの内容も記載しています。)

elasticsearch.yml

cluster.name: "docker-cluster"
network.host: 0.0.0.0

# minimum_master_nodes need to be explicitly set when bound on a public IP
# set to 1 to allow single node clusters
# Details: <https://github.com/elastic/elasticsearch/pull/17288>
discovery.zen.minimum_master_nodes: 1

http.cors.enabled: true
http.cors.allow-origin: /https?:\\/\\/localhost(:[0-9]+)?/
http.cors.allow-headers: X-Requested-With, Content-Type, Content-Length, x-amz-security-token, X-Amz-Date, Authorization