CertbotによるLet’s Encryptの証明書の取得

WebサーバーでのHTTPS通信を実現するためにLet’s Encryptの証明書の取得方法を記す。

概要

WebサーバーでのHTTPS通信を実現するには,Webサーバーの公開鍵証明書 (証明書) と秘密鍵を用意する必要がある。秘密鍵は自分で用意できるとしても,公開鍵証明書は第三者の認証局 (CA: Certificate Authority) に発行してもらう必要がある。一般的には,証明書の発行は有料であるため,ネックだった。

これを回避するために,自己署名証明書という自分で発行した証明書を開発環境で使うことがある (参考: OpenSSLによる自己署名証明書の作成)。ただ,当然ながら自分自信で発行している以上,信頼性に乏しい。加えて,自己署名証明書で運用されているWebサイトは,Webブラウザーが警告を出す。そのため,本番環境での運用には使えない。

こういう事情もあり,WebサイトのHTTPS化はなかなかやっかいな問題だった。

そんな中,2015年頃からHTTPSによる安全なWeb普及させるためにLet’s Encryptという無償で証明書を発行するプロジェクトが始まった。

Let’s Encryptを使うことで個人でもお金をかけずに証明書を発行でき,WebサイトのHTTPSを低コストで実現できる。そこで,Let’s Encryptでの証明書の発行方法を調べて成功したので手順を記す。

前提条件

Let’s Encryptによる証明書の発行はACMEというプロトコルに沿って実施される。もっとも,基本的にはACME対応クライアントソフトを使ったコマンド実行で行う。

その他,「Challenge Types – Let’s Encrypt – Free SSL/TLS Certificates」に書かれている通り,Let’s Encryptのサーバーから通信を行う。

そこで,以下の2点が前提として必要になる。

Let’s Encryptでの証明書発行の前提条件
  1. http://<YOUR_DOMAIN>/.well-knwon/acme-challenge/にHTTP (ポート80) でアクセス可能
  2. サーバー上でシェルコマンドを実行可能
  3. 証明書の有効期限が90日なのでそれまでに更新が必要

これを念頭においておく。

Certbot

ACMEクライアントとして,公式で推奨されているCertbotを使用する。

まず,Certbotをインストールする。CertbotはPython3で実装されており,基本的に管理者権限での実行を前提として作られている。が,ユーザー権限でも実行はできるようになっている (参考: Certbot – Frequently Asked Questions)。

管理者権限だと融通が効かないので,ユーザー権限でインストール・実行する。

インストール

Certbotのインストール手順は「Get Certbot — Certbot 1.6.0.dev0 documentation」に記されている。

Python 2.7 or 3.5+が必要になる。Pythonがなければ「インストール: Python | 数値解析が得意な現代的なインタープリター型言語」を参考にインストールしておく。

マニュアルでは,基本的には以下のどちらかの方法でインストールする。

  • OSのパッケージマネージャー
  • certbot-autoコマンドのダウンロード

ただ,どちらも管理者権限が必要となり,今回のユーザー権限での実行と方針が合わない。かといって,ソースコードからのインストールはハードルが高い。

そこで,今回はpip3でインストールする。pipでのインストールは「Other Operating System – Get Certbot — Certbot 1.6.0.dev0 documentation」で以下の通り記載されているように,公式では推奨されていない。

Warning

Please do not use python certbot/setup.py install, python pip install certbot, or easy_install certbot. Please do not attempt the installation commands as superuser/root and/or without virtual environment, e.g. sudo python certbot/setup.py install, sudo pip install, sudo ./venv/bin/…. These modes of operation might corrupt your operating system and are not supported by the Certbot team!

Other Operating System – Get Certbot — Certbot 1.6.0.dev0 documentation

OSの設定がおかしくなる可能性があるので,管理者権限や仮想環境以外の環境で実行しないように書かれている。

ただ,今回はユーザー権限での実行であり,OSの設定を編集するわけではない。ユーザー権限で実行する限り,問題が起きてもユーザー権限の範囲で対応でき,実際に特に問題がなかった。そのため,公式では推奨されていないが,pipでインストールする。

インストール自体は以下のコマンドを実行するだけで簡単だ。

pip3 install --user certbot==1.6.0

今回はPython 3.8.4でCertbot 1.6.0をインストールした。

証明書の取得

Certbotをインストールしたので,これを使って証明書を取得する。

Certbotのコマンドラインオプションは「Certbot command-line options – User Guide — Certbot 1.6.0.dev0 documentation」に掲載されている。

Certbotはサブコマンドとオプションの組み合わせで処理を行う。

Certbot – Frequently Asked Questions」に記載がある通り,Certbotはデフォルトで管理者領域の/etc/letsencrypt/, /var/log/letsencrypt/, /var/lib/letsencrypt/に書き込むので,これらを--config-dir, --logs-dir, --work-dirでユーザー領域に変更することがポイントとなる。続いて,管理者権限の不要なプラグインである--webroot--manualを使う。

Webroot – User Guide — Certbot 1.6.0.dev0 documentation」にあるとおり,ローカルWebサーバーを使っており,証明書の発行中にWebサーバーを停止させたくない場合,certonlyサブコマンドと--webrootオプションを併用する。さらに,-wでWebルート (DocumentRoot) を指定する。

具体的には,以下のコマンドで証明書を発行する。

LOCAL=$([ $(id -u) = 0 ] && echo /usr/ || echo ~/.)local
DOMAIN=aws.senooken.cf
EMAIL=contact@$DOMAIN
certbot certonly --webroot -w $LOCAL/var/www/$DOMAIN -d $DOMAIN -m $EMAIL \
--agree-tos --no-eff-email \
--config-dir=$LOCAL/etc/letsencrypt \
--logs-dir=$LOCAL/var/log/letsencrypt \
--work-dir=$LOCAL/var/lib/letsencrypt

--config-dir, --logs-dir, --work-dirを,それぞれデフォルトの/から~/.localに起点を変更してインストールする。

説明を省いたオプションを以下に整理した。

オプションの説明
オプション説明
-w webrootDocumentRootを指定。このディレクトリーの.well-knownを通信に使う。
-d domain発行対象のドメインを一つ指定する。
-m email有効期限の期限などを受け取るメールアドレスを指定する。
--agree-tos利用規約へ同意する。
--no-effi-emailメーリングリストへの加入を辞退する。

コマンドを実行すると以下のようにメッセージが表示される。

Saving debug log to /home/ec2-user/.local/var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for aws.senooken.cf
Using the webroot path /var/www/aws.senooken.cf for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Non-standard path(s), might not work with crontab installed by your operating system package manager

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /home/ec2-user/.local/etc/letsencrypt/live/aws.senooken.cf/fullchain.pem
   Your key file has been saved at:
   /home/ec2-user/.local/etc/letsencrypt/live/aws.senooken.cf/privkey.pem
   Your cert will expire on 2020-10-17. 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"
 - Your account credentials have been saved in your Certbot
   configuration directory at /home/ec2-user/.local/etc/letsencrypt.
   You should make a secure backup of this folder now. This
   configuration directory will also contain certificates and private
   keys obtained by Certbot so making regular backups of this folder
   is ideal.
 - 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

メッセージにある通り,--config-dirで指定したディレクトリー (例: $HOME/.local/etc/letsencrypt) のlive/<domain>/fullchain.pemに証明書,privkey.pemに秘密鍵が保存された。

以上で証明書と秘密鍵の発行は完了となる。後は,サーバー (httpd, nginxなど) の設定でこれらのファイルを参照すればよい (参考: Apache HTTP ServerでのHTTPSの設定方法)。

証明書の更新

証明書の更新は「Renewing certificates – User Guide — Certbot 1.6.0.dev0 documentation」にあるとおり,renewサブコマンドを使う。コマンドがcertonlyからrenewに変わることと-dオプションが不要な点以外は同じだ。

LOCAL=$([ $(id -u) = 0 ] && echo /usr/ || echo ~/.)local
DOMAIN=aws.senooken.cf
EMAIL=contact@$DOMAIN
certbot renew \
-m $EMAIL --agree-tos --no-eff-email \
--webroot -w $LOCAL/var/www/$DOMAIN --config-dir $LOCAL/etc/letsencrypt \ --logs-dir $LOCAL/var/log/letsencrypt --work-dir $LOCAL/var/lib/letsencrypt \

Let’s Encryptの証明書は有効期限が90日間なので,期限切れの前に更新する。通信の失敗を考慮して,30日 (1か月) に一度上記コマンドを実行するように,crontabに登録する。

crontab <<-"EOT"
* * * */1 * (LOCAL=/home/senooken/.local DOMAIN=aws.senooken.cf EMAIL=contact@$DOMAIN; $LOCAL/bin/certbot renew -q -m $EMAIL --agree-tos --no-eff-email --webroot -w $LOCAL/var/www/$DOMAIN --config-dir $LOCAL/etc/letsencrypt --logs-dir $LOCAL/var/log/letsencrypt --work-dir $LOCAL/var/lib/letsencrypt)
EOT

コマンド実行時に-qオプションでエラー以外の出力を抑制している。

最後にcronを再起動する。

sudo systemctl restart cron

これで1か月ごとに証明書が更新されるはずだ。

ワイルドカード証明書

証明書発行時のドメインを [*.senooken.cf] のようにワイルドカード (*) を使って複数指定した証明書をワイルドカード証明書という。ワイルドカード証明書があれば,1個の証明書で複数のドメインに対応することができ,1サーバーでの複数のドメイン運用時に証明書の管理の手間が省ける。

Let’s Encryptは2018-03-13からワイルドカード証明書に対応している。ワイルドカード証明書の発行は通常と若干異なる手順を取る。手順の中で,証明書の発行・更新時にDNSの検証を行うためにDNSサーバーでTXTレコードを登録する必要がある。この処理の自動化がなかなかややこしい。

現時点ではDNSにCloudflareを使うか,DNSサーバーにBindを使っていれば,対応可能らしい。ただ,現時点ではワイルドカード証明書が必要ではないので,今後のための調査内容を残す。

以下の公式情報を参考にした。

参考

ワイルドカード証明書の発行には,以下の4点がポイントとなる。

ワイルドカード証明書発行のポイント
  • --server https://acme-v02.api.letsencrypt.org/directory: サーバーの指定 (今は不要)。
  • --preferred-challenges dns: DNSプラグインの指定。
  • --manual: Manualプラグインの指定。自分のサーバー以外のドメインの証明書の取得に必要。
  • -d *.domain: ワイルドカードを使用したドメインの指定。コンマ (,) 区切りか複数-dを指定。

デフォルトのHTTP-01チャレンジと異なり,DNSサーバーのTXTレコードの内容を確認する。そのため,--webroot -w /var/www/htmlの指定が不要になり,代わりに--manual --preferred-challenges dns --manual -d senooken.cf,*.senooken.cfを指定する。IPアドレスのログへの記録の問い合わせをスキップするため,--public-ip-logging-okも指定する。

具体的には以下のようなコマンドを実行する。

LOCAL=~/.local
certbot certonly --agree-tos --no-eff-email \
-d senooken.cf -m contact@example.com \
--config-dir=$LOCAL/etc/letsencrypt \ --logs-dir=$LOCAL/var/log/letsencrypt \ --work-dir=$LOCAL/var/lib/letsencrypt \
--manual --preferred-challenges dns \
--manual-public-ip-logging-ok -d \*.senooken.cf

このコマンドを実行すると以下が表示される。

Saving debug log to /home/ec2-user/.local/var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for senooken.cf
dns-01 challenge for senooken.cf

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.senooken.cf with the following value:

w3VAqlZug3iaX6XUlAflopqwfVHWYTnvcZaUXh1lOr8

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

ここでドメイン業者のDNSサーバーのTXTレコードに以下の内容相当の登録が要求される。

_acme-challenge.senooken.cf TXT w3VAqlZug3iaX6XUlAflopqwfVHWYTnvcZaUXh1lOr8

登録を済ませてからEnterを入力すると,証明書が発行される。

ただし,更新時も同じTXTレコードの登録が必要になる。

TXXレコードの登録も自動化して更新処理を全て自動化する場合,以下の情報源を参考にする。

ワイルドカード証明書の自動更新の参考情報

今回はワイルドカード証明書の発行を断念したので,ここに残した情報を参考に,将来の挑戦時に改めて整理する。

結論

Let’s Encryptによる公開鍵証明書の発行方法を記した。

HTTPS化の実現でここ何年かで名前をよく聞いていたLet’s Encryptだが,今回実際に自分で使ってようやくどういうものかわかった。

デフォルトの挙動が管理者権限を前提としており,ユーザー権限での動作の確認に少し時間がかかった。

その他,ワイルドカード証明書の存在に気づき,こちらにも挑戦しようとしたところ,思っていたより難しく,思いの外情報の整理に手こずった。

ひとまず,今回の手順でWebサーバーのHTTPS化ができるようになったので,実際に自分のWebアプリケーションを公開してみたい。

CertbotによるLet’s Encryptの証明書の取得” に対して2件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です