Certbot を使い3分で無料の SSL 証明書を取得する

2020.05.06

はじめに

Certbot を使った SSL/TLS サーバ証明書の取得方法を紹介します.
認証局は Let's Encrypt で, 主要なブラウザから信頼された認証局とみなされています.

料金は無料, 作業時間は3分程度です.

前提

証明書を発行する際, 認証局は発行依頼主が対象ドメインを所有していることを確認する必要があります.
Let's Encrypt は対象ドメインの特定のパスから検証用のファイルをダウンロードし, その中身を検証することでドメイン所有の確認を行なっています.
この Let's Encrypt とのやりとりや検証用ファイルの用意を行うのが Certbot です.
そのため, 作業は証明書を設置したいサーバ上で実施する必要があります.
また, そのサーバ上で ウェブサーバが稼働しており, 対象のドメインで HTTP 接続できる必要があります.

例えば, demo.shinsuke.classmethod.info ドメインの証明書を取得する場合, 下記の状態であれば作業可能です.

$ # 対象ドメインの正引きの結果と現在ログインしているサーバの IP アドレスが一致していることを確認
$ dig demo.shinsuke.classmethod.info

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.amzn2.0.2 <<>> demo.shinsuke.classmethod.info
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46767
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;demo.shinsuke.classmethod.info.    IN  A

;; ANSWER SECTION:
demo.shinsuke.classmethod.info. 60 IN   A   54.199.99.27

$ curl ifconfig.me
54.199.99.27

$ # 対象ドメインに HTTP 接続できることを確認
$ curl -I http://demo.shinsuke.classmethod.info/
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Wed, 06 May 2020 03:43:26 GMT
Content-Type: text/html
Content-Length: 3520
Last-Modified: Mon, 23 Sep 2019 22:08:38 GMT
Connection: keep-alive
ETag: "5d894266-dc0"
Accept-Ranges: bytes

SSL/TLSサーバ証明書取得手順

実際に証明書の取得からウェブサーバへの設置まで行います.
今回 OS は Amazon Linux2, ウェブサーバには Nginx を使っています.
SSL サーバ証明書を設置したいサーバにログインし, 下記コマンドを実行します.

$ sudo amazon-linux-extras install -y epel
$ sudo yum install -y certbot python2-certbot-nginx
$ sudo certbot --nginx

最後のコマンドを実行すると登録用メールアドレスや認証を受けたいドメイン名の入力を求められます.
入力例です.
メールアドレスやドメイン名は実際にものに変更してください.

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): yokota.shinsuke@classmethod.jp

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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: N
No names were found in your configuration files. Please enter in your domain
name(s) (comma and/or space separated)  (Enter 'c' to cancel): demo.shinsuke.classmethod.info
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for demo.shinsuke.classmethod.info
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/nginx.conf

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/nginx.conf

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled
https://demo.shinsuke.classmethod.info

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=demo.shinsuke.classmethod.info
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/demo.shinsuke.classmethod.info/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/demo.shinsuke.classmethod.info/privkey.pem
   Your cert will expire on 2020-08-03. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /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

Nginx の設定ファイルも自動で編集されるので, これで作業完了です.
すぐに対象ドメインへ HTTPS 接続できます.

SSL/TLS サーバ証明書更新手順

証明書の期限は90日間と比較的短めです.
ただ, Certbot には更新用のコマンドが用意されており, コマンドを定期実行することで証明書を自動で更新することができます.
また, 更新の前後で任意のコマンドを実行させることも可能です. 下記の例では更新後に Nginx の設定再読み込みをしています.

$ sudo /usr/bin/certbot renew --post-hook "/bin/systemctl reload nginx.service"
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/demo.shinsuke.classmethod.info.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/demo.shinsuke.classmethod.info/fullchain.pem expires on 2020-08-03 (skipped)
No renewals were attempted.
No hooks were run.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

有効期限が30日未満の場合は証明書が更新され, 期限が30日以上ある場合は上の例のように処理がスキップされます.
自動で更新させたい場合は次のような cron を仕込むと良いでしょう.

$ cat /etc/cron.d/renew-cert
0 0 * * * root /usr/bin/certbot renew --post-hook "/bin/systemctl reload nginx.service"

設定内容確認

Certbot を使うことで証明書の取得からウェブサーバの設定まで自動で実行されました.
何が行われたのか確認してみます.

ドメインの所有確認

Nginx のアクセスログを見ると Let's Encrypt から検証用のアクセスがあったことが確認できます.

$ sudo grep letsencrypt /var/log/nginx/access.log
34.209.232.166 - - [05/May/2020:09:03:37 +0000] "GET /.well-known/acme-challenge/X1Fb4lHwzKjFEqLYJbxkMYioaH5zmoyRSiX3jk-rv5c HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" "-"
52.15.254.228 - - [05/May/2020:09:03:37 +0000] "GET /.well-known/acme-challenge/X1Fb4lHwzKjFEqLYJbxkMYioaH5zmoyRSiX3jk-rv5c HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" "-"
66.133.109.36 - - [05/May/2020:09:03:37 +0000] "GET /.well-known/acme-challenge/X1Fb4lHwzKjFEqLYJbxkMYioaH5zmoyRSiX3jk-rv5c HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" "-"
18.196.96.172 - - [05/May/2020:09:03:38 +0000] "GET /.well-known/acme-challenge/X1Fb4lHwzKjFEqLYJbxkMYioaH5zmoyRSiX3jk-rv5c HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" "-"

SSL/TLS サーバ証明書の取得

取得した証明書は /etc/letsencrypt/ 以下に保存されます.
今回は Nginx の設定まで Certbot を使って行いましたが, ウェブサーバの設定を手動でやる場合はここのファイルを参照します.

$ sudo tree /etc/letsencrypt/
/etc/letsencrypt/
|-- accounts
|   `-- acme-v02.api.letsencrypt.org
|       `-- directory
|           `-- 0fe0918fc88faeea54448fb268c4935c
|               |-- meta.json
|               |-- private_key.json
|               `-- regr.json
|-- archive
|   `-- demo.shinsuke.classmethod.info
|       |-- cert1.pem
|       |-- chain1.pem
|       |-- fullchain1.pem
|       `-- privkey1.pem
|-- csr
|   `-- 0000_csr-certbot.pem
|-- keys
|   `-- 0000_key-certbot.pem
|-- live
|   |-- README
|   `-- demo.shinsuke.classmethod.info
|       |-- README
|       |-- cert.pem -> ../../archive/demo.shinsuke.classmethod.info/cert1.pem
|       |-- chain.pem -> ../../archive/demo.shinsuke.classmethod.info/chain1.pem
|       |-- fullchain.pem -> ../../archive/demo.shinsuke.classmethod.info/fullchain1.pem
|       `-- privkey.pem -> ../../archive/demo.shinsuke.classmethod.info/privkey1.pem
|-- options-ssl-nginx.conf
|-- renewal
|   `-- demo.shinsuke.classmethod.info.conf
|-- renewal-hooks
|   |-- deploy
|   |-- post
|   `-- pre
`-- ssl-dhparams.pem

Nginx の設定変更

Certbot によって加えられた変更です.
対象ドメイン用の server ブロックが追加され, SSLディレクティブ部分も自動で設定されていることが確認できます.
今回は元々の nginx.conf に対象ドメイン用の設定が無かったので server ブロックごと追加されていますが, すでに対象ドメイン用の設定がある場合は適切な server ブロック内にSSLディレクティブが追加されます. Certbot による設定と既存の設定が衝突することはありません. 設定ファイルが自動で書き換えられるのが不安であれば, 初回実行時は念のため /etc/nginx/ 全体のバックアップをとってから Certbot を使っても良いでしょう.
また, 今回は HTTP での接続があった場合は HTTPS にリダイレクトするよう指定したため, リダイレクト用の設定も Certbot により追加されていることが確認できます.

$ diff -ur /etc/nginx.orig/ /etc/nginx/
diff -ur nginx.orig/nginx.conf nginx/nginx.conf
--- nginx.orig/nginx.conf       2019-09-23 22:09:40.000000000 +0000
+++ nginx/nginx.conf    2020-05-05 09:03:49.907087389 +0000
@@ -86,5 +86,47 @@
 #        }
 #    }

+
+
+    server {
+    server_name demo.shinsuke.classmethod.info; # managed by Certbot
+        root         /usr/share/nginx/html;
+
+        # Load configuration files for the default server block.
+        include /etc/nginx/default.d/*.conf;
+
+        location / {
+        }
+
+        error_page 404 /404.html;
+            location = /40x.html {
+        }
+
+        error_page 500 502 503 504 /50x.html;
+            location = /50x.html {
+        }
+
+
+    listen [::]:443 ssl ipv6only=on; # managed by Certbot
+    listen 443 ssl; # managed by Certbot
+    ssl_certificate /etc/letsencrypt/live/demo.shinsuke.classmethod.info/fullchain.pem; # managed by Certbot
+    ssl_certificate_key /etc/letsencrypt/live/demo.shinsuke.classmethod.info/privkey.pem; # managed by Certbot
+    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
+    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
+
 }

+    server {
+    if ($host = demo.shinsuke.classmethod.info) {
+        return 301 https://$host$request_uri;
+    } # managed by Certbot
+
+
+        listen       80 ;
+        listen       [::]:80 ;
+    server_name demo.shinsuke.classmethod.info;
+    return 404; # managed by Certbot
+
+
+}}
+

まとめ

Certbot を使って簡単に無料の SSL/TLS 証明書を取得する方法を紹介しました.
CloudFront や ELB を使う場合であれば, ACM が発行する無料 SSL/TLS 証明書が利用できます. しかし, EC2 インスタンス上の ウェブサーバに直接接続する場合や CloudFront のオリジンとして EC2 インスタンスを利用する場合は自分で証明書を取得し設置しなければなりません.
Certbot を使えば手間も費用もかけずに証明書の取得および設定ができるので試してみてください.

参考 URL