概要
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でエラーになってしまいます。
Elasticseachの設定ファイル(elasticsearch.yml)に、CORS関連設定の追記が必要そうです。
CORSの許可
Cross-Originを許可するよう、以下の設定を追記しました。
elasticsearch.yml
http.cors.enabled: true
http.cors.allow-origin: /https?:\\/\\/localhost(:[0-9]+)?/
再度トライ
まだエラーが出ます。 エラーの内容が少し変わってます。
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