tl;dr
Amazon ES のアクセス制御を IP だけでしかやったことなかったので、実運用を考慮すると IAM role で制御する場合の方法を模索してみましたの Ruby 版。
参考
- http://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomain-configure-access-policies
- http://stackoverflow.com/questions/34229015/can-i-use-amazons-elasticsearch-with-rails-searchkick-gem-securely
- https://github.com/elastic/elasticsearch-ruby
- https://github.com/winebarrel/faraday_middleware-aws-signers-v4
- http://qiita.com/deme0607/items/8024deb3ff0fcd7e95ba
ありがとうございます。
memo
構成
構成は前回と同様。
- EC2 には AmazonESFullAccess ポリシーを付与した IAM role がアタッチされている
- Amazon ES にはポリシー未適用
さんぷるスクリプト
ということで、参考として上げさせて頂いた記事を真似て以下のようなスクリプトをこさえてみました。
require 'elasticsearch' require 'faraday' require 'faraday_middleware/aws_signers_v4' require 'json' es_endpoint = 'https://your_domain-xxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com' role_name = 'your_role_name' region = 'ap-northeast-1' def get_credential metadata_url = 'http://169.254.169.254' conn = Faraday.new(:url => metadata_url) do |faraday| faraday.adapter Faraday.default_adapter end response = conn.get '/latest/meta-data/iam/security-credentials/dev' credential = JSON.parse(response.body) return { 'access_key': credential['AccessKeyId'], 'secret_key': credential['SecretAccessKey'], 'token': credential['Token'] } end credentials = get_credential() es = Elasticsearch::Client.new(url: es_endpoint) do |faraday| faraday.request :aws_signers_v4, credentials: Aws::Credentials.new(credentials[:access_key], credentials[:secret_key], credentials[:token]), service_name: 'es', region: region end puts JSON.dump(es.info)
github.com
この Gem が肝です。前回の Python と同様に署名付きリクエストという壁が立ちはだかりますが、この gem が AWS 署名バージョン 4 を良しなに扱ってくれます。ありがたや、ありがたや。
実行してみると…
# # 環境の確認 # $ cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) $ ruby -v ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux] # # 必要な gem をインストール # $ cat Gemfile source "https://rubygems.org" gem 'elasticsearch' gem 'faraday_middleware-aws-signers-v4' $ bundle install --path vendor/bundle # # スクリプトを実行 # $ bundle exec ruby sample.rb | jq . { "name": "Space Turnip", "cluster_name": "1234567890123:your_domain", "version": { "number": "2.3.2", "build_hash": "0944b4bae2d0f7a126e92b6133caf1651ae316cc", "build_timestamp": "2016-05-20T07:46:04Z", "build_snapshot": false, "lucene_version": "5.5.0" }, "tagline": "You Know, for Search" }
おわり
先人の方々の努力のおかげでなんとかなりそうです。ありがとうございました。
おまけ : docker コンテナから Amazon ES にアクセスする場合
ファイル達
上記のサンプルを sample.py で保存。
$ tree . . ├── Dockerfile ├── Gemfile └── sample.rb 0 directories, 3 files
Dockerfile
FROM ruby:2.3.1-alpine MAINTAINER inokappa RUN apk --update add tzdata && \ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ apk del tzdata && \ rm -rf /var/cache/apk/* RUN mkdir /app COPY . /app WORKDIR /app RUN bundle install --path vendor/bundle && \ bundle clean ENTRYPOINT ["bundle", "exec", "ruby"]
build して run
$ docker build -t es-sample-ruby . $ docker run --rm es-sample-ruby sample.rb | jq . { "cluster_name": "1234567890123:your_domain", "tagline": "You Know, for Search", "version": { "lucene_version": "5.5.0", "build_hash": "0944b4bae2d0f7a126e92b6133caf1651ae316cc", "number": "2.3.2", "build_timestamp": "2016-05-20T07:46:04Z", "build_snapshot": false }, "name": "Space Turnip" }