Auto renew SSL Certificate with Certbot(Let’s Encrypt)
このブログのSSL証明書はLet’s Encryptという認証局のものを使っています。Let’s Encryptの証明書を使い始めてしばらく経ちましたがいいかんじです。
Let’s Encryptについて
Let’s Encryptの証明書は無料で提供されており、certbotという証明書の取得や更新をコマンドで行うことの出来るツールが提供されているのが特徴です。神ってことです。
証明書の有効期限は90日(3ヶ月)と短いですが、コマンド一発で証明書を更新できるのでデメリットではありません。
また、証明書を細かくアップデートしていけるということは常に最新の暗号技術を取り入れた証明書を(Let’s Encryptが追随してくれているので)使えるということであり、度々世間を騒がせている弱い暗号方式を使った証明書によって起きる脆弱性に対しても運用上強いはずです。
certbotをインストールする
Let’s Encryptの証明書はcertbotを通じて取得、更新を行うので、まずはcertbotを導入します。
certbotのサイトの案内に従い使用しているWebサーバとOSを選択していきます。
Webサーバまで選ばせているのは、certbotコマンドが対応しているWebサーバであればWebサーバの設定まで行ってくれるのでその案内のためです。
h2oは選択肢にはないのでNon of the above
を選択しました。選択するとディストリビューションに応じたインストール方法を案内するページに遷移します。
CentOS7の場合はepelリポジトリからインストールできるので非常に楽です。
sudo yum install epel-release
sudo yum install --enablerepo=epel certbot
CentOS6は若干面倒です(特に構成管理に含めようとすると...)。
証明書を取得する
certbotで証明書を取得するコマンドは以下です(webrootプラグインを使った方法)。
certonly
: 証明書ファイルを取得--webroot
: webrootプラグインを使用--webroot-path
: Let’s Encryptが認証のためにアクセスすることのできるpathを指定(そのドメインのドキュメントルート以下のpathを指定すればok)--domains
: 証明書を取得したいドメイン名--email
: そのドメインの所有者のメールアドレス--agree-tos
: yesコマンド的なやつ。このオプションがないと対話モードで同意する必要がある
sudo certbot certonly --webroot --webroot-path <証明書を取得したいドメインでアクセスできるpath> --domains <ドメイン名> --email <メールアドレス> --agree-tos
certbotコマンドを実行すると、webroot-path以下に.well-known
ディレクトリが作成され、そこに一時的な認証トークンが設置されます。その場所へLet’s Encryptがアクセスしてきて、アクセスできればそのドメインの所有者であることが証明されるという流れです。
なのでドメインのドキュメントルートがWebアプリケーションの場合は、Let’s Encrypt用にディレクトリを作成してあげる必要があります(何もしないとappにリダイレクトされて404になるので)。
h2oでの設定イメージ。
hosts:
"blog.lorentzca.me:80":
listen:
port: 80
paths:
"/":
proxy.reverse.url: "http://127.0.0.1:2368/"
"/.well-known":
file.dir: /var/www/ghost/.well-known
コマンドが成功すると、以下のようなディレクトリツリーが作成されます。
/etc/letsencrypt/
├── accounts
│ ├── acme-staging.api.letsencrypt.org
│ │ └── directory
│ │ └── xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
│ └── acme-v01.api.letsencrypt.org
│ └── directory
│ └── yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
├── archive
│ ├── ドメイン名
├── csr
├── keys
├── live
│ ├── ドメイン名
└── renewal
証明書はarchive/ドメイン名
以下にファイルが置かれ、世代管理されます。live/ドメイン名
以下に最新の世代の証明書のファイルがシンボリックリンクされています。
Webサーバに設定する際には、live/ドメイン名
ディレクトリ以下のprivkey.pem
とfullchain.pem
(証明書&中間証明書)を指定すればOKです。
証明書を取得し終わったら(SSLにリダイレクトさせる場合は)Webサーバの設定をかえる必要があります(443ポートでLet’s Encrypt認証用pathを受けられるようにする)。
hosts:
"blog.lorentzca.me:443":
listen:
port: 443
ssl:
certificate-file: "/etc/letsencrypt/live/blog.lorentzca.me/fullchain.pem"
key-file: "/etc/letsencrypt/live/blog.lorentzca.me/privkey.pem"
paths:
"/":
proxy.reverse.url: "http://127.0.0.1:2368/"
"/.well-known":
file.dir: /var/www/ghost/.well-known
証明書を更新する
更新はかんたんで、以下のコマンドを実行するだけです。複数の証明書がある場合でも、以下のコマンドでOKです。
renew
: SSL証明書の更新を実行--post-hook
: SSL証明書が置き換わった場合に実行する任意のコマンド
sudo certbot renew --post-hook "好きなコマンド"
--post-hook
オプションには、systemctl reload nginx
のようにWebサーバが証明書を読み込み直せるようなコマンドを指定してあげます。
renewコマンドは、実行されると証明書の期限を確認し、1ヶ月を切っていたら実際に証明書を更新します。なのでcronなどで毎日実行しても大丈夫です。
証明書をsystemd.timerを使い定期的に行う
cronなどで上記のrenewコマンドを定期的に叩けば、人間の手を介さずSSL証明書を更新することができます。神...!!! ✨
cronでもいいですが私はせっかくの(?)systemdなので、systemd.timerを使って定期実行しています。
以下の2ファイルを/etc/systemd/system/
以下に設置します(h2oがWebサーバ)。
- serviceで定期実行したいコマンドを定義
- timerで定期実行したいコマンドを定義したserviceを指定し、指定した時間に実行
certbot.service
[Unit]
Description=Certbot renew service
After=h2o.target
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --post-hook "systemctl restart h2o"
[Install]
WantedBy=default.target
certbot.timer
[Unit]
Description=Renew Certification every day
[Timer]
OnBootSec=1min
OnCalendar=*-*-* 04:00:00
Unit=certbot.service
[Install]
WantedBy=timers.target
設置後はsystemdに読み込ませてあげます。
sudo systemctl daemon-reload
timerは以下のように確認することができます。
$ sudo systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
水 2017-03-08 02:09:56 JST 5h 47min left 火 2017-03-07 02:09:56 JST 18h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
水 2017-03-08 04:00:00 JST 7h left 火 2017-03-07 04:00:01 JST 16h ago certbot.timer certbot.service
2 timers listed.
Pass --all to see loaded but inactive timers, too.
自動更新された様子
去年の9月に自動更新された様子を激写。journalctl -x -u certbot
で確認しました。
9月 19 04:00:14 ponpokopon.me systemd[1]: Starting Certbot renew service...
-- Subject: Unit certbot.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit certbot.service has begun starting up.
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: Processing /etc/letsencrypt/renewal/ponpokopon.me.conf
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: new certificate deployed without reload, fullchain is
9月 19 04:00:27 ponpokopon.me certbot[17305]: /etc/letsencrypt/live/ponpokopon.me/fullchain.pem
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: Processing /etc/letsencrypt/renewal/ghost.ponpokopon.me.conf
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: new certificate deployed without reload, fullchain is
9月 19 04:00:27 ponpokopon.me certbot[17305]: /etc/letsencrypt/live/ghost.ponpokopon.me/fullchain.pem
9月 19 04:00:27 ponpokopon.me certbot[17305]: -------------------------------------------------------------------------------
9月 19 04:00:27 ponpokopon.me certbot[17305]: Congratulations, all renewals succeeded. The following certs have been renewed:
9月 19 04:00:27 ponpokopon.me certbot[17305]: /etc/letsencrypt/live/ponpokopon.me/fullchain.pem (success)
9月 19 04:00:27 ponpokopon.me certbot[17305]: /etc/letsencrypt/live/ghost.ponpokopon.me/fullchain.pem (success)
9月 19 04:00:27 ponpokopon.me systemd[1]: Started Certbot renew service.
-- Subject: Unit certbot.service has finished start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit certbot.service has finished starting up.
--
-- The start-up result is done.
感想
もうとにかく楽で素晴らしい。普通の証明書を更新する場合はだいたい以下の手順が必要です。
- CAのサイトへ行って対象ドメインの証明書更新を開始する
- CSRを貼り付けたり、認証方法の確認をしたりする
- 設定を確認後、入金する
- しばらくして承認メールが来るので承認ボタンを押す
- メールで証明書が納品される
- 納品された証明書をサーバに設置しWebサーバをreload
これがコマンド一発ってやばい!!
certbotにはwebrootプラグイン以外にもstandaloneやnginxプラグインがあります。また認証フローはACMEプロトコルというプロトコルが使われているようです。
機会があればそのあたりについても調べてみようと思っています。
参考
公式サイト。
日本語ページ。
Let’s Encryptを支えるACMEプロトコルについて。
systemd.timerについて。