Elasticsearch&KibanaのHTTPS対応 in Docker Container
概要
この記事ではDocker Composeで動かしているElasticsearchとKibanaをHTTPS対応して、ローカルで立ち上げたKibanaのAlert機能を使えるようにします (追記:現在Elasticの有料プランに入らなければAlert機能は一部に制限されているようです)。
基本的には、以下の記事の通り設定します。とても分かりやすい記事でした、ありがとうございました。
上記記事からの変更点としては、秘密鍵/公開鍵は毎回生成せず一度だけ作成してローカルに配置し、Docker Compose実行時に読み込むようにしています。なぜなら、外部からElaticsearchを叩くときに公開鍵が必要になるからです。
方法
HTTPS通信に必要な鍵の作成と配置
まずはHTTPS通信に利用する鍵を作成します。Elasticsearchが提供しているスクリプトを使うため、この作業もDockerを用います。以下のコードは、参考記事でsetup
コンテナが実行していた部分をただDocker単体で実行できるように展開しただけです。以下の様にDockerfile
とsetup.sh
を作成します。
# Dockerfile
FROM docker.elastic.co/elasticsearch/elasticsearch:8.8.1
USER root
COPY setup.sh /usr/local/bin/setup.sh
RUN chmod +x /usr/local/bin/setup.sh
CMD ["/bin/bash", "-c", "/usr/local/bin/setup.sh"]
#!/bin/bash
if [ ! -f config/certs/ca.zip ]; then
echo "Creating CA"
bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip
unzip config/certs/ca.zip -d config/certs
fi
if [ ! -f config/certs/certs.zip ]; then
echo "Creating certs"
echo -ne \
"instances:\n"\
" - name: es01\n"\
" dns:\n"\
" - es01\n"\
" - localhost\n"\
" ip:\n"\
" - 127.0.0.1\n"\
> config/certs/instances.yml
bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key
unzip config/certs/certs.zip -d config/certs
fi
あとはDockerを実行して鍵を作成し、ローカルにコピーします。
# build & run
$ docker build -t es_for_cert .
$ docker run --name es_for_cert -v certs:/usr/share/elasticsearch/config/certs es_for_cert
# 鍵をローカルにコピーし展開
$ mkdir -p config/certs
$ docker cp es_for_cert:/usr/share/elasticsearch/config/certs/certs.zip config/certs/certs.zip
$ docker cp es_for_cert:/usr/share/elasticsearch/config/certs/ca.zip config/certs/ca.zip
$ unzip config/certs/ca.zip -d config/certs
$ unzip config/certs/certs.zip -d config/certs
Docker Composeの準備
次にdocker-compose.yml
と.env
を作成します。
docker-compose.yml
volumesで先ほど作成しローカルにコピーした./config/certs
を、ElasticsearchとKibanaのコンテナにそれぞれ渡します。また、Kibanaのenvironmentで指定しているELASTICSEARCH_HOSTS
は、HTTPSのURLです。
version: "3"
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:8.8.1
container_name: es
environment:
- node.name=es01
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- bootstrap.memory_lock=true
- discovery.type=single-node
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=true
- xpack.security.http.ssl.key=certs/es01/es01.key
- xpack.security.http.ssl.certificate=certs/es01/es01.crt
- xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.http.ssl.verification_mode=certificate
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.key=certs/es01/es01.key
- xpack.security.transport.ssl.certificate=certs/es01/es01.crt
- xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.license.self_generated.type=${LICENSE}
ulimits:
memlock:
soft: -1
hard: -1
ports:
- 9200:9200
volumes:
- es-data:/usr/share/elasticsearch/data
- ./config/certs:/usr/share/elasticsearch/config/certs
# kibana
kibana:
depends_on:
- es01
image: docker.elastic.co/kibana/kibana:8.8.1
container_name: kibana
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=https://es01:9200
- SERVERNAME=kibana
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
- ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
- XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${ENCRYPTIONKEY}
volumes:
- ./config/certs:/usr/share/kibana/config/certs
- kibana-data:/usr/share/kibana/data
volumes:
certs:
driver: local
es-data:
driver: local
kibana-data:
driver: local
あとは.env
の作成です。ここでENCRYPTIONKEY
には何らかの文字列を入れる必要がありますが、openssl rand -base64 32
などのコマンドで作成できます。
# .env
ELASTIC_PASSWORD=elastic
KIBANA_PASSWORD=elastic
LICENSE=trial
ENCRYPTIONKEY=hogehoge
実行と確認
最後にDocker Composeでコンテナを起動して、ElasticsearchとKibana間で正しく通信できているかを確認します。
$ docker compose up
http://localhost:5601/ にアクセスして、無事にKibanaが起動していればOKです。
(捕捉) Pythonによるアクセス
このようにして起動したElasticsearchにリクエストを投げるには、HTTPSでアクセスしなければいけません。そのため、下記のようにElasticsearchのクライアントを作成する必要があります。ここではパスワードや鍵のパスをハードコードしていますが、これも.env
ファイルに記載するなどしたほうが良いでしょう。
In [1]: from elasticsearch import Elasticsearch
...:
...: es = Elasticsearch(
...: ['https://localhost:9200'],
...: basic_auth=('elastic', 'elastic'),
...: ssl_show_warn=False,
...: verify_certs=True,
...: ca_certs='/path/to/config/certs/ca/ca.crt'
...: )
...: print(es.info())
{'name': 'es01', 'cluster_name': 'docker-cluster', (中略) 'tagline': 'You Know, for Search'}
Discussion