2019年4月14日日曜日

CentOS7.6における2019年4月14日現在でのLet's encryptの証明書の取得方法

*** この記事は2019年4月14日現在のものです。 ***

Let's encryptって得られるのはサーバ証明書だけですが、その目的のためならばオレオレ証明書を作るよりよほど簡単に証明書が得られて本当に助かります。
androidやiosのようなオレオレ証明書を使うための設定が難しかったりする端末がある環境だと、ことさらありがたさが身に沁みます。

ただ、困ったことに、Let's Encryptの情報を検索すると、古いのと新しい情報がぐっちゃぐっちゃに混在した状況で、まことに混乱をしてしまいます。

そこで、本日、実際にCentOS7.6上でcertbotを用いてLet's Encryptの証明書を取得する機会を得ましたので、その手順と結果を記録しておきます。
当然ながらこの手順で得られた証明書は、apache,postfix,dovecotをはじめとしてサーバ証明書を利用できるアプリケーションで使いまわせます。

前提条件
  1. epelリポジトリから取得できるcertbot 0.31.0を使用して証明書を得る。
    理由:2019年4月14日にyum install certbot でインストールされるcertbotのバージョンが0.31.0だというだけの話です。
  2. 複数のサブドメインに対応した証明書を求めるがワイルドカードな証明書は求めない。
    理由:サブドメイン毎に証明書を変えられるのと、http-01での認証が可能なため、ワイルドカードな証明書を得るために必要なdns-01の場合に必須となるdnsのTXTの更新が不要だからです。
  3. Webサーバの構築が正しく行われていること。
    言い直すと、申請するドメイン名およびサブドメイン名すべてでhttp経由で/.well-known/acme-challenge/ ディレクトリの中身が外部から読み出せること。
    理由:ACME v2でhttp-01を用いて認証してもらうために一時的にLet's Encrypt サーバからトークンを取得して/.well-known/acme-challenge/ ディレクトリに配置し、Let's Encryptのサーバから読み出してもらうことで認証を行うためです。
    ドットから始まるファイルやディレクトリを外部から見えない設定にしていたり、アクセス元をIPアドレスやドメイン名などで制限していると失敗します。
    なお、このディレクトリはcertbotコマンドが勝手に掘って、認証が終わり次第削除されます。
    httpのポート番号はデフォルトでは80ですが、certbotに --http-01-port オプションを与えると、ポート番号を変更できます。
    https経由で認証をしてもらうtls-sni-01はもはや利用できません。
では実際に申請してみたいと思います。
このサンプルではドメイン名一つ(xxx.yyy)と5つのサブドメイン名を一度に認証して1つにまとめた証明書を発行してもらうコマンドでテストしてみる例を示します。

certbot certonly \
    --dry-run \
    --agree-tos \
    --webroot \
    -w /home/httpd/site0 -d xxx.yyy \
    -w /home/httpd/site1 -d site1.xxx.yyy \
    -w /home/httpd/site2 -d site2.xxx.yyy \
    -w /home/httpd/site3 -d site3.xxx.yyy \
    -w /home/httpd/site4 -d site4.xxx.yyy \
    -w /home/httpd/site5 -d site5.xxx.yyy \
    -m 更新切れ通知などを受け取るメールアドレス

certbotへ与えたオプションはそれぞれ以下の通りです。
  • certonly
    証明書の取得だけを行います。
  • --dry-run
    実際には証明書の取得を行わずに、取得の手順を一通り行ってくれます。
    Webサーバの設定が誤っていないかどうかもチェックしてもらえますので、いきなり証明書を取得せずにこのオプションをつけてテストすることをお勧めします。
    当然、証明書を実際に取得する際にはこのオプションを外して実行してください。
  • --agree-tos
    利用規約を読みもせずに無条件にやみくもに受け入れます。
    初回くらいこのオプションを外して読んだほうがいいとは思いますが、思うだけです。
  • --webroot
    この後に続く-wオプションで指定されたディレクトリにcertbotが/.well-known/acme-challenge/ディレクトリを掘って、トークンを配置して、-dで指定されたドメイン名でLet's Encryptサーバがアクセスを行い、読み出しを行って認証するhttp-01手順で行うことを指示しています。
  • -w と -d のペア
    -wは--webroot-pathの省略形です。-dで定義されるドメイン名のドキュメントルートディレクトリを記述します。
    -dは--domainsおよび--domainの省略形です。ドメイン名を表します。
    なお、-wは-dより先に記述する必要があります。
    その理由は、-dで指定されたドメイン名のドキュメントルートディレクトリは、直前の-wで指定された値を使うということになっているためです。
    この理由で、各ドメインで/.well-known/acme-challenge/以下を共有する設定にしてあるなら、一対一で記述する必要は特にありません。
上記コマンドを実行すると、一回だけ
Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom.
と聞かれて、Yes/Noの入力を求められます。電子フロンティア財団の最新情報などが欲しければYesに、更新時期が近付いたなどの通知が欲しいだけならNoを選択することになるかと思います。

この選択が終わったら実際のテストが始まります。
各ドメイン名に実際にアクセスが行われ、その結果が逐次表示されていきます。
すべてうまくいけば、
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
云々と表示されます。
エラーが出たら「おめでとう」とは言ってくれません。エラーになった原因が明確に示されますので、その情報に基づいて修正を行ってください。

おめでとう、と言われたら、IMPORTANT NOTES:欄ではどこに何の証明書を作ったか、その証明書の失効日はいつか、ということが明記されていますので一応一通り目を通しておいてください。

今回の場合は/etc/letsencrypt/live/ドメイン名/にドメイン名とサブドメイン名がまとめて証明された証明書が1つ配置されていますので、各サーバに証明書を適用していきます。
  • httpd 2.4.6-88(CentOS7.6ではapache2.4.6)
    今回申請した各VirtualHostにサーバ証明書(cert.pem)と秘密鍵(privkey.pem)と中間証明書(chain.pem)を設定します。
    SSLCertificateFile /etc/letsencrypt/live/ドメイン名/cert.pem
    SSLCertificateKeyFile  /etc/letsencrypt/live/ドメイン名/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/ドメイン名/chain.pem
  • postfix 2.10.1-7
    /etc/postfix/main.cfでサーバ証明書+中間証明書(fullchain.pem)と秘密鍵を設定します。fullchain.pemの中身はcert.pemとchain.pemが1ファイルにまとまっているものです。
    smtpd_tls_cert_file = /etc/letsencrypt/live/ドメイン名/fullchain.pem
    smtp_tls_cert_file = /etc/letsencrypt/live/ドメイン名/fullchain.pem
    smtpd_tls_key_file = /etc/letsencrypt/live/ドメイン名/privkey.pem
    smtp_tls_key_file = /etc/letsencrypt/live/ドメイン名/privkey.pem
  • dovecot 2.2.36-3
    /etc/dovecot/conf.d/10-ssl.conにpostfixと同様にサーバ証明書+中間証明書と秘密鍵を設定します。
    ssl_cert = </etc/letsencrypt/live/ドメイン名/fullchain.pem
    ssl_key = </etc/letsencrypt/live/ドメイン名/privkey.pem
それぞれ、設定が終わったら
systemctl reload httpd
systemctl reload postfix
systemctl reload dovecot
を行って設定を適用してください。

ここまでで各サーバに証明書が適用されました。

今度は、証明書の自動更新を行う手続きを定義します。
Let's Encryptの証明書の有効期限は90日固定なので、手動で更新するにはちと煩瑣ですので、cronで毎日更新を試みることにする場合は、/etc/cron.dailyに以下の内容を実行するシェルスクリプトを配置してください。

/usr/bin/certbot renew --quiet --max-log-backups 10 --post-hook "systemctl reload httpd;systemctl reload postfix; systemctl reload dovecot"

オプションの意味は以下の通りです。
  • renew
    更新が必要な証明書だけ更新します。
    更新が必要なドメイン、サブドメインなどの情報は、ドメインを申請したときの情報が/etc/letsencrypt/renewal/ドメイン名.confに保存されていますので、この情報をもとに更新を行ってくれます。
    有効期限が差し迫らない限り(現状では30日前)更新しません。一日二回がお勧めとのことですが、まあ、1回でいいでしょう。
  • --quiet
    エラー時を除いてメッセージを出力しません。
  • --max-log-backups 10
    デフォルトだと/var/log/letsencrypt/letsencrypt.log.*が最大1000個できちゃうので、せめて10個くらいにしてくださいというお願いです。
  • --post-hook
    更新がうまくいった際に実行するコマンドを定義します。
    この場合はhttpdとpostfixとdovecotに証明書をリロードさせています。
このコマンドをテストする場合は、--dry-runをオプションに加えてください。
そうすると、実際には更新を行いませんが、更新がかかったものとして--post-hookの内容を含めて実行してくれますので、一回は手動でやっておいたほうがいいと思います。

以上です。
お読みいただいてありがとうございました。

0 件のコメント:

コメントを投稿