Let's Encrypt! (with Docker / HAProxy)

〜 Let's Encrypt を Docker 上に HAProxy で対応した覚書 〜

Let's Encrypt (CA (Certificate Authority) の一種) サービスを使って、 無料〜 (寄付を募っている) で SSL/TLS サーバー証明書を発行してもらうことができる。
すなわち web サーバを、 まともな証明書 (自己署名でない) で https 化することが出来る。

一般的な話としてサーバー証明書といっても色々なレベルがある。
商用レベルに用いるサーバー証明書だと、 例えばそれが会社ならその登記簿等まで確認する (有料の) CA が一般に必要とされる。
Let's Encrypt の場合は、 ドメインが有効であるかどうかまでの確認となるようだ。

以下に従って行う (順にリンクをたどっていける)。

手順

この手順では、 既に HAPropxy や web サーバが動いていたらいったん止める必要がある。

また、 Let's Encrypt のサーバから HAProxy の 80 番ポートにアクセスできる必要がある。

1. HAProxy の Dockerfile で certbot をインストールするようにする

FROM haproxy:1.8
〜
RUN apt-get update && apt-get install -y certbot
〜
(apt-get update と apt-get install は同じ RUN で && で連結しなければならない。 Dockerfile のベストプラクティス を参照)

この certbot は、 証明書の自動更新も行うなら、 このように Docker イメージにそのまま持っておく必要がある。
(この手順では証明書の自動更新までは行わない)

2. HAProxy の Docker イメージを build し run する

(ビルド手順は省略)

$ docker run -it --rm -p 80:80 -v tmp_letsencrypt:/etc/letsencrypt 127.0.0.1:5000/my_haproxy /bin/bash

docker run のコマンドラインの最後に /bin/bash を指定することにより、 haproxy の docker-entrypoint.sh の場合は haproxy の代わりに /bin/bash が起動する。
コンテナ内の /etc/letsencrypt が tmp_letsencrypt という named volume を参照することにより、 取得した証明書を外から取り出すことができる。

3. HAProxy のコンテナ内で certbot を実行

# certbot certonly --standalone --preferred-challenges http -d ドメイン.名 -d www.ドメイン.名

--preferred-challenges http が無いと、 443 番ポートの方を見に行くもよう。
-d 〜 はいくつでも指定できるもよう。

Let's Encrypt のサーバから 80番ポートへのアクセスが制限されていると Timeout になったりする。

だいたい以下のようになれば成功。

root@d10b45736849:/# certbot certonly --standalone --preferred-challenges http -d ドメイン.名 -d www.ドメイン.名
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for ドメイン.名
http-01 challenge for www.ドメイン.名
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/ドメイン.名/fullchain.pem. Your cert will expire
   on 2018-03-18. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
   renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

問題ないなら、 exit で抜ける。

4. fullchain.pem と privkey.pem を取り出す・結合する

以下の fullchain.pem や privkey.pem は、 ../../archive/ドメイン.名/ 以下を指すシンボリックリンクになっている。

[nsmrtks@test ~]$ sudo -i

[root@test _data]# cd /var/lib/docker/volumes/tmp_letsencrypt/_data/live/ドメイン.名/

[root@test ドメイン.名]# cat fullchain.pem privkey.pem > ~nsmrtks/server.pem

[root@test ドメイン.名]# exit

5. 結合したファイルを HAProxy で参照できるようにする

Dockerfile の例

〜
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
COPY server.pem /usr/local/etc/haproxy/server.pem
〜

haproxy.cfg の例

global
〜
	# https (SSL/TLS)
	# これが無いとこのような警告が出る
	#	Setting tune.ssl.default-dh-param to 1024 by default,
	#	if your workload permits it you should set it to at
	#	least 2048. Please set a value >= 1024 to make this
	#	warning disappear.
	tune.ssl.default-dh-param 2048

defaults
〜

frontend http-in
	bind *:80
	default_backend servers

	# https (SSL/TLS)
	bind *:443 ssl crt /usr/local/etc/haproxy/server.pem

backend servers
	server server1 web:80 maxconn 32

以上


index