Elasticsearch & Kibana をLet's EncryptでTLS対応させる

# やりたいこと

「[Elasticsearch 7.6 と Kibana 7.6 に Security を有効化してDockerで起動する（コピペ）](https://qiita.com/hsano/items/79031c7e23f252c8daeb) 」をやったものの、最終的にやりたかった[Fastly](https://www.fastly.jp)からのLoggingの宛先にするにはTLS周りが厳しかったので、[Let's Encrypt](https://letsencrypt.org/ja/)で証明書を手配することにした。
むしろこっちの方が簡単だったので作業の履歴メモとして残しておく。

# 前提

- Dockerが使える
- ホスト側がRAM 4GB以上で、Elasticsearchに2GB、Kibanaに1GBを割当てられる（Amazon Lightsail あるいは MacBook Pro）
- ドメインを持っていてDNSがいじれる（仮に example.com とする）
- Let's Encrypt はDNS認証でワイルドカード証明書を発行する
- Elasticsearchを `elasticsearch.example.com` で運用するようDNSが構成済み
- Kibanaを `kibana.example.com` で運用するようDNSが構成済み

# ほぼコピペでイケる一式

## 1. Elasticsearchのデータを保存したり証明書一式を保存する場所を作る

- Elasticsearchのコンテナにボリュームを割当てるときにパーミッションエラーが出たら要調整

```shell
mkdir -p ~/Development/Docker/Elasticsearch/data ~/Development/Docker/Elasticsearch/cert
```

## 2. Let's Encryptで証明書を手配する

- certbotのDockerイメージを使うことでAmazon Linux上で、ホストを汚さずに作業する
- 途中、認証用にDNSへTXTレコードを追加するように指示があるので、DNSにレコードを追加してしばらくしてから継続する

```shell
docker run -it \
--name certbot \
-v ~/Development/Docker/Elasticsearch/cert:/etc/letsencrypt \
certbot/certbot certonly \
--manual \
-d *.example.com \
-m info@example.com \
--agree-tos \
--manual-public-ip-logging-ok \
--preferred-challenges dns-01 \
--server https://acme-v02.api.letsencrypt.org/directory
```

## 3. ElasticsearchとKibanaに証明書を組み込むDockerfileを用意する

- 作業しやすい場所に移動

```shell
cd ~/Development/Docker/Elasticsearch
```

- `dockerfile-es` というファイル名でElasticsearch用Dockerfileを作る

```Dockerfile
FROM docker.elastic.co/elasticsearch/elasticsearch:7.6.0

RUN \
elasticsearch-plugin install --batch analysis-icu && \
elasticsearch-plugin install --batch analysis-kuromoji

RUN mkdir /usr/share/elasticsearch/config/cert
ADD "./cert/archive/example.com" /usr/share/elasticsearch/config/cert
RUN chown -R root:elasticsearch /usr/share/elasticsearch/config/cert
```

- `dockerfile-kibana` というファイル名でKibana用Dockerfileを作る

```Dockerfile
FROM docker.elastic.co/kibana/kibana:7.6.0

ADD "./cert/archive/example" /etc/kibana/cert
```

## 4. Dockerイメージをビルドする

```shell
docker build -f dockerfile-es -t elasticsearch-tls .
docker build -f dockerfile-kibana -t kibana-tls .
```

## 5. Elasticsearchを起動する

```shell
docker run --name Elasticsearch -d \
--restart=always \
-m 2048m \
-p 9200:9200 \
-p 9300:9300 \
-e cluster.name=ES \
-e discovery.type=single-node \
-e network.host=0.0.0.0 \
-e xpack.security.enabled=true \
-e xpack.monitoring.collection.enabled=true \
-e "ES_JAVA_OPTS=-Xms1024m -Xmx1024m" \
-e "ELASTIC_PASSWORD=iY69DxipKifV7utYA4t6jgxT" \
-e xpack.security.transport.ssl.enabled=true \
-e xpack.security.transport.ssl.key=/usr/share/elasticsearch/config/cert/privkey1.pem \
-e xpack.security.transport.ssl.certificate=/usr/share/elasticsearch/config/cert/fullchain1.pem \
-e xpack.security.http.ssl.enabled=true \
-e xpack.security.http.ssl.key=/usr/share/elasticsearch/config/cert/privkey1.pem \
-e xpack.security.http.ssl.certificate=/usr/share/elasticsearch/config/cert/fullchain1.pem \
-v ~/Development/Docker/Elasticsearch/data:/usr/share/elasticsearch/data \
--ulimit nproc=4096:4096 \
--ulimit memlock=256000:256000 \
--ulimit nofile=65536:65536 \
elasticsearch-tls
```

## 6. Kibana用ユーザーのパスワードを設定する

- 前提にある通り、この時点で `elasticsearch.example.com` でElasticsearchにアクセスできることが必要

```shell
curl -XPUT --user elastic:iY69DxipKifV7utYA4t6jgxT 'https://elasticsearch.example.com:9200/_xpack/security/user/kibana/_password' -H "Content-Type: application/json" -d '{
  "password" : "6ezji8D5jvceXUsTsvg8mAY4"
}'
```

## 7. Kibanaを起動する

- Elasticsearchとの通信はDocker内で `es-internal.example.com` で行うように構成する。ドメインを合わせないと証明書が機能しないため。

```shell
docker run --name Kibana -d \
--restart=always \
--link Elasticsearch:es-internal.example.com \
-m 1280m \
-p 443:5601 \
-e "ELASTICSEARCH_HOSTS=https://es-internal.example.com:9200" \
-e "ELASTICSEARCH_USERNAME=kibana" \
-e "ELASTICSEARCH_PASSWORD=6ezji8D5jvceXUsTsvg8mAY4" \
-e "SERVER_SSL_ENABLED=true" \
-e "SERVER_SSL_CERTIFICATE=/etc/kibana/cert/fullchain1.pem" \
-e "SERVER_SSL_KEY=/etc/kibana/cert/privkey1.pem" \
--ulimit nproc=4096:4096 \
--ulimit memlock=256000:256000 \
--ulimit nofile=65536:65536 \
kibana-tls
```

## 8. 必要な設定をする

- `https://kibana.example.com/` にアクセスして `elastic` ユーザーとしてログイン