share facebook facebook2 twitter menu hatena pocket slack

2016.09.20 TUE

IAM Role を付与した EC2 インスタンスから Amazon ES にアクセスするメモ(Python 版)

川原 洋平

WRITTEN BY 川原 洋平

tl;dr

Amazon ES のアクセス制御を IP だけでしかやったことなかったので、実運用を考慮すると IAM role で制御する場合の方法を模索してみました。

参考

memo

構成

  • EC2 には AmazonESFullAccess ポリシーを付与した IAM role がアタッチされている
  • Amazon ES にはポリシー未適用

この状態で Amazon ES にアクセスしてみると…

$ curl https://your_domain-xxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com/
{"Message":"User: anonymous is not authorized to perform: es:ESHttpGet on resource: your_domain"}

リクエストに認証情報を埋め込んであげる必要があるようです。curl の場合にはどーやるのかな…と思ったら…

残念ながら curl で実現するのは難しいようです。

さんぷるスクリプト

ということで、参考として上げさせて頂いた記事を真似て以下のようなスクリプトをこさえてみました。

from elasticsearch import Elasticsearch, RequestsHttpConnection
from requests_aws4auth import AWS4Auth
import requests
import json, os

region      = 'ap-northeast-1'
es_endpoint = 'your_domain-xxxxxxxxxxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com'
role_name   = 'your_role_name'

def get_credential():
    metadata_url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/' + role_name
    response     = requests.get(metadata_url)
    credential   = json.loads(response.text)

    return { 'access_key': credential['AccessKeyId'],
             'secret_key': credential['SecretAccessKey'],
             'token': credential['Token'] }

credentials = get_credential()

awsauth     = AWS4Auth(
    credentials['access_key'],
    credentials['secret_key'],
    region,
    'es',
    session_token=credentials['token']
)

es = Elasticsearch(
    hosts=[{'host': es_endpoint, 'port': 443}],
    http_auth=awsauth,
    use_ssl=True,
    verify_certs=True,
    connection_class=RequestsHttpConnection
)

print json.dumps(es.info())


pypi.python.org

requests-aws4auth という AWS リクエストに認証情報を追加するAWS 署名バージョン 4を良しなに扱ってくれるモジュールを利用することでシンプルなコードになっていると思います。
実行してみると…

#
# 環境の確認
#
$ cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
$ python -V
Python 2.7.5

#
# 必要なモジュールを導入
#
$ cat requirements.txt
boto3
elasticsearch
requests
requests_aws4auth
$ sudo pip install -r requirements.txt

#
# スクリプトを実行
#
$ python test.py | 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": "Rage"
}

おわり

先人の方々の努力のおかげでなんとかなりそうです。ありがとうございました。

おまけ : docker コンテナから Amazon ES にアクセスする場合

ファイル達

上記のサンプルを sample.py で保存。


$ tree .
.
├── Dockerfile
├── requirements.txt
└── sample.py

0 directories, 3 files

Dockerfile

FROM python:2.7.12-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 pip install -r requirements.txt
ENTRYPOINT ["python"]

build して run

$ docker build -t es-sample-python .
$ docker run --rm es-sample-python sample.py | 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"
}

元記事はこちら

IAM Role を付与した EC2 インスタンスから Amazon ES にアクセスするメモ(Python 版)