🔏

Elasticsearch&KibanaのHTTPS対応 in Docker Container

2023/09/09に公開

概要

この記事ではDocker Composeで動かしているElasticsearchとKibanaをHTTPS対応して、ローカルで立ち上げたKibanaのAlert機能を使えるようにします (追記:現在Elasticの有料プランに入らなければAlert機能は一部に制限されているようです)。

基本的には、以下の記事の通り設定します。とても分かりやすい記事でした、ありがとうございました。

https://zenn.dev/proyuki02/articles/7830ae0b51fc98

上記記事からの変更点としては、秘密鍵/公開鍵は毎回生成せず一度だけ作成してローカルに配置し、Docker Compose実行時に読み込むようにしています。なぜなら、外部からElaticsearchを叩くときに公開鍵が必要になるからです。

方法

HTTPS通信に必要な鍵の作成と配置

まずはHTTPS通信に利用する鍵を作成します。Elasticsearchが提供しているスクリプトを使うため、この作業もDockerを用います。以下のコードは、参考記事でsetupコンテナが実行していた部分をただDocker単体で実行できるように展開しただけです。以下の様にDockerfilesetup.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.ymlvolumesで先ほど作成しローカルにコピーした./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