Let's Encrypt 導入


はじめに

このサイトのHTTPSはとりあえず自己証明書の設定だけしておりましたが、Googleの常時SSL化推進でChromeも非HTTPSサイトには「保護されていない通信」と表示されたりと、いよいよ本格化してきたので、真面目に対応させることにしました。

SSLサーバ証明書の種類

今まで知らなかったけど、SSLサーバ証明書には種類があるみたいなのでざっくり調べてみました。
EV認証
認証レベル3
企業認証(OV)
認証レベル2
ドメイン認証(DV)
認証レベル1
暗号化
所有者の確認
組織実在性の確認-
実在性の確認--
対象法人法人法人・個人
信頼性
特徴信頼性
アドレスバー緑表示
ワイルドカード不可
実在性証明
ワイルドカード発行
低コスト
スピード発行
この内、Let's Encryptはドメイン認証に該当します。個人で使うなら十分です。なんと言っても無料ですからね。しっかり利用してHTTPS普及促進に貢献します!

Let's Encrypt 導入手順

環境

今回はApacheの環境にLet's Encryptを導入します。
バージョン参照
CentOS 77.4.1708
OpenSSL1.1.0gOpenSSL 1.1.0 導入
Apache2.4.29Apache 2.4.29 導入
MySQL5.7.21MySQL 5.7.21 導入
PHP 7.2.1PHP 7.2.1 導入
WordPress4.9.2WordPress ダウンロードと設定

インストール

EPELリポジトリをインストール
# yum install epel-release
EPELリポジトリ指定して、certbot python-certbot-apacheをインストール
# yum install --enablerepo=epel certbot python-certbot-apache
certbotコマンドを実行して、SSL/TLSサーバ証明書の取得。
# certbot certonly --agree-tos --webroot -w /var/www/html/eastforest.jp -d eastforest.jp -d www.eastforest.jp -m <mail address>

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org

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.

(Y)es/(N)o:
Electronic Frontier Foundation にメールアドレスを共有してよいか聞かれてきますが、今回はNoにしました。自動化を考えるとここもオプションで指定したかったですが、見つからず・・・

[オプション内容]
--agree-tos:利用規約に同意
--webroot:DocumentRoot 配下に認証用のファイルを設置することで認証・証明書取得
-w : DocumentRootのパス (--webrootを指定したときに必要)
-d : サーバのドメイン
-m : メールアドレス(更新期限近くにメールが来るらしい)
--no-eff-email : EFFのメールアドレス共有拒否 ※certbot --help register で見つけることができました。

Yesと入力すると以下のように表示されて終了
IMPORTANT NOTES:
Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/eastforest.jp/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/eastforest.jp/privkey.pem
Your cert will expire on 2019-03-22. 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
上記のメッセージに表示されたシンボリックリンクを確認。
Apacheの設定にはこちらのリンクを指定するようにします。
証明書の更新時はこれらのシンボリックリンクが自動的に新しい方の鍵・証明書にリンクするように自動で書き変わってくれるようです。
# ls -l /etc/letsencrypt/live/eastforest.jp/
total 4
lrwxrwxrwx 1 root root 37 Dec 22 15:47 cert.pem -> ../../archive/eastforest.jp/cert1.pem
lrwxrwxrwx 1 root root 38 Dec 22 15:47 chain.pem -> ../../archive/eastforest.jp/chain1.pem
lrwxrwxrwx 1 root root 42 Dec 22 15:47 fullchain.pem -> ../../archive/eastforest.jp/fullchain1.pem
lrwxrwxrwx 1 root root 40 Dec 22 15:47 privkey.pem -> ../../archive/eastforest.jp/privkey1.pem
上記シンボリックリンクの実態は以下
# ls -l /etc/letsencrypt/archive/eastforest.jp/
total 16
-rw-r--r-- 1 root root 1931 Dec 22 15:47 cert1.pem
-rw-r--r-- 1 root root 1647 Dec 22 15:47 chain1.pem
-rw-r--r-- 1 root root 3578 Dec 22 15:47 fullchain1.pem
-rw------- 1 root root 1708 Dec 22 15:47 privkey1.pem
ここからはApache 2.4の設定になります。
環境によって設定箇所が変わってくると思います。 このサイトの環境はhttpd.confの設定でhttpd-vhosts.confとhttpd-ssl.confをIncludeしてます。
# egrep 'ssl|vhost' /usr/local/httpd/conf/httpd.conf | grep Include
Include conf/extra/httpd-vhosts.conf
Include conf/extra/httpd-ssl.conf
httpd-vhosts.conf側でhttpsの設定をいれているので、こちら側だけにSSL証明書と鍵を入れておけば良いかと思いましたが、httpd-ssl.confをIncludeしているのでこちらもSSLが機能するようにSSL証明書を設定しておく必要がありました。
ただ同じ設定するのはイタダケない・・・
httpd-ssl.confをコメントアウトしてhttp.confにIncludeしなければよいのですが、httpd-ssl.conf側でログの設定をしてたりしたので、httpd-vhosts.conf側にLet's Encryptの設定、httpd-ssl.confに元々設定してあった自己証明書の設定をしておきました。
httpd-vhosts.confのSSLCertificate***の3つの部分が今回追加したLet's Encryptの設定に必要な箇所になります。
# egrep -v '^\s*#|^$' /usr/local/httpd/conf/extra/httpd-vhosts.conf
<irtualHost *:80>
  DocumentRoot "/var/www/html/eastforest.jp"
  ServerName www.eastforest.jp
  ServerAlias eastforest.jp
</VirtualHost>
<VirtualHost *:443>
  DocumentRoot "/var/www/html/eastforest.jp"
  ServerName www.eastforest.jp
  ServerAlias eastforest.jp
  Protocols h2 http/1.1
  SSLEngine on
  SSLCertificateFile "/etc/letsencrypt/live/eastforest.jp/cert.pem"
  SSLCertificateKeyFile "/etc/letsencrypt/live/eastforest.jp/privkey.pem"
  SSLCertificateChainFile "/etc/letsencrypt/live/eastforest.jp/chain.pem"
</VirtualHost>
httpd-ssl.confのSSLCertificate***設定はとりあえず自己証明書を入れときました。
# egrep -v '^\s*#|^$' /usr/local/httpd/conf/extra/httpd-ssl.conf | grep -A 9 _default_
<VirtualHost _default_:443>
Protocols h2 http/1.1
DocumentRoot "/var/www/html"
ServerName *****:443
ServerAdmin *****@*****
ErrorLog "|/usr/local/httpd-2.4.29/bin/rotatelogs logs/ssl_error_log.%Y%m%d 86400 540"
CustomLog "|/usr/local/httpd-2.4.29/bin/rotatelogs logs/access_log.%Y%m%d 86400 540" combinedio
SSLEngine on
SSLCertificateFile "/usr/local/httpd-2.4.29/conf/server.crt"
SSLCertificateKeyFile "/usr/local/httpd-2.4.29/conf/server.key"
コンフィグのチェック
# apachectl configtest
Apache再起動
# systemctl restart httpd
ブラウザのアドレスバーに鍵マークが表示されればOKです。

自動更新

Let's EncryptのSSL/TLSサーバ証明書の有効期限は90日になります。残り30日未満になったら、更新が可能となります。
やり方は簡単でコマンド1発で更新してくれます。有効期限30日未満になっていない場合はスキップされるだけです。
# certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

Processing /etc/letsencrypt/renewal/eastforest.jp.conf

Cert not yet due for renewal

The following certs are not due for renewal yet:
/etc/letsencrypt/live/eastforest.jp/fullchain.pem expires on 2019-03-22 (skipped)
No renewals were attempted.
自動化も簡単で以下のコマンドをcronで設定しておけば良さそう。更新可能な時(更新期間残り30日未満)だけ実行されるため、cronで定期的に実行していても、そのたびにApacheが再起動されることもないようです。
certbot renew --post-hook "systemctl reload httpd.service" 
ホント楽で便利!

【2019/03/09 追記】
実際に更新可能期間になり、cronで実行したが失敗。
cronで実行するコマンドは以下で実施。
certbot renew --pre-hook "systemctl stop httpd.service" --post-hook "systemctl start httpd.service"
私の理解が足りてなかったようで、このやり方はstandaloneプラグインを使ったときにやり方でした。standaloneプラグインはcertbotクライアントに内蔵されている簡易的なWebサーバが一時的に使われるため、Port80とPort443が被らないように--pre-hookでapacheを止めておく必要があります。 今回はwebrootプラグインによる更新なのでapacheを止める必要はない、というか止めてはいけませんでした。実際手動で"certbot renew"を実行したときは問題なく更新されました。なので本記事の本文のところは修正しておきましたが、cronで"certbot renew"してapacheに反映させるなら、以下をcronに設定すると良いと思います。
certbot renew --post-hook "systemctl reload httpd.service" 
上記コマンドだと実際更新期間にならないと処理が行われないので、問題があったときに発見が遅れます。なので併せて強制更新のドライランを試すか、これもcronに入れておいてログで確認するようにした方が良いです。
certbot renew --force-renewal --dry-run --post-hook "systemctl restart httpd.service" 
ログはデフォルトなら以下かと。
ls -lrt /var/log/letsencrypt/ | tail -5
-rw-r--r-- 1 root root 18464 Mar 9 14:08 letsencrypt.log.4
-rw-r--r-- 1 root root 40366 Mar 9 14:09 letsencrypt.log.3
-rw-r--r-- 1 root root 971 Mar 9 14:10 letsencrypt.log.2
-rw-r--r-- 1 root root 40366 Mar 9 15:18 letsencrypt.log.1
-rw-r--r-- 1 root root 970 Mar 9 15:56 letsencrypt.log
次回こそcronで更新成功していれば、また追記することもないと思います。 参考

SSLサーバー証明書の違い
SSL/TLS証明書無料化は進むか? ~Let's Encryptに見る無料SSL/TLS証明書の台頭とその注意点~
Let's Encrypt 総合ポータル (非公式解説サイト)
CentOS 7 + Apache 2.4 に Let’s Encrypt の証明書を導入する手順