2017年3月20日月曜日

MyDNS と Let's Encrypt を使って,FreeBSD 上の apache24 を https 化してみた(その3)

 FreeBSD 上の apache24 で運用している個人サイトの https 化(通信の暗号化)の話の(その3)である。
目次
 (a) その1:MyDNS を使って web サーバーをたてる
 (b) その2:オレオレ認証を使った https 化
 (c) その3:Let's Encrypt を使ったサーバー認証(今回)
 (d) その4:vhost や ssl などの apache24 の設定
 (e) その5:サイトの内容に関する注意点(最終)

 今回は Let's Encrypt でサーバー証明書(正しくはドメイン認証)を取得して,より安全な通信を確保する話をしてみよう。

 Let's Encrypt は,無料でドメイン証明書を発行してくれるサービスであり, いろんな企業が後援しているらしい。 Let's Encrypt は日本語サイトなので,ハードルは高くはないと思う。 ちなみに,使い方は Let's Encrypt の使い方や, ユーザーガイドを見るといいと思う。 コマンドは コマンド一覧に記載がある。

 Let's Encrypt を使う際の注意点としては,
 「一定期間内に取得できる認証数に制限(上限)がある」
 「認証要求時に apache を止めないといけないことがある(止めない方法もあるらしい)」
 「認証の証明書の有効期限は90日なので,更新が必要」
などがある。

最初の注意点は,Rate Limits にあるように一定期間に可能な認証取得数に制限があることがあげられる。
ざっと読み取ると(間違ってるかもしれないのでご注意を…)
  (1) ドメイン (registered domain) 当り,週に最大20個までしか認証できない。次の週になれば,さらに最大20個まで認証可能。
  (2) 1個の認証につき,最大 100 個までコンピュータ名を登録できる。
  (3) 全く同じ認証に対しては,週に最大5回までしか認証できない。
という感じみたい。

 少しややこしいが,MyDNS.JP 等の場合には,この制限が効いてくる。
どういうことかと言うと,例えば,
  hogehoge.mydns.jp
というドメインに,
   ・www.hogehoge.mydns.jp
   ・poyo.hogehoge.mydns.jp
   ・kero.hogehoge.mydns.jp
という3台のサーバーがあり,認証を受けたいとしよう。
さらに「www.hogehoge.mydns.jp」は独自ドメインを取得して「www.hogehoge.com」でもアクセスできるようにしたいとしよう。
 この場合,認証を受けるには,とりあえず「hogehoge.mydns.jp」ドメインの中のどれか1台のサーバー(例えば「www.hogehoge.mydns.jp」)の認証を受けよう。うまくいけば同じドメイン内にある他の2台も簡単に追加することができる(最大で100台までだが…)。
 それとは別に「www.hogehoge.com」でも認証を受ける必要がある。同じマシンでもドメイン名が違う「別名」を持たせるには,別に認証が必要になる,ためである。

 Let's Encrypt で認証を受ける単位はドメインごとである。 上記の例では「hogehoge.mydns.jp」と「hogehoge.com」の2個のドメインに対して認証を受けることになる。 「hogehoge.com」の方は独自ドメインで問題ないのだが,「hogehoge.mydns.jp」はちょっと問題になる。 実は,「hogehoge.mydns.jp」の場合,認証の対象となるドメイン(registered domain)は「mydns.jpとなってしまうみたい。

 Let's Encrypt 側から見ると「hogehoge.mydns.jp」は「mydns.jp」のサブドメインと見えるみたい。 そうなると,数多くいる MyDNS.JP の利用者が短い期間で「xxxx.mydns.jp」というドメイン名で認証を受けたい,とすると, 「mydns.jp」ドメインに対して一週間で最大20個の認証,という制限にひっかかってしまうことになる(みたい)。 そのため,
An unexpected error occurred:
There were too many requests of a given type :: Error creating new cert :: Too many certificates already issued for: mydns.jp
Please see the logfiles in /var/log/letsencrypt for more details.

IMPORTANT NOTES:
 - If you lose your account credentials, you can recover through
   e-mails sent to email@address.com.
 - Your account credentials have been saved in your Certbot
   configuration directory at /usr/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.
のようなエラーとなってしまう。
 これにひっかかると,次の週まで待たないと仕方ないみたい。 あるいは別のドメイン名を取得して,そのドメイン名で認証を受けるしかないみたい。
ちなみにドメインごとの登録情報はhttps://crt.sh/ で確認することができる。

 2個目の注意点としては,Let's Encrypt で認証を受けるには幾つかのコマンドがあるが,1個を除き(「Webrootプラグイン」), web サーバーを少しの期間(10秒程度)止めないといけない,点がある。 個人で作っているサイトなら問題ないかもしれないが,大きなサイトだと一瞬たりとも web サーバーを止めたくない,ということがあるかもしれない。 そのような場合は「Webroot プラグイン」を使った認証に挑戦しないといけないみたいである。 ここでは「Webroot プラグイン」ではなく「Standalone プラグイン」を使うので,認証や更新時には web サーバーを止めないといけない。

 最後の注意点としては,Let's Encrypt で受けた認証(ドメイン認証)の証明書には90日間という有効期限がある点である。 有効期限が近づくと,メールアドレスが登録してあれば,30日前になるとメールが届くらしい。 その時点で更新すればいいが,cron を使えば簡便に自動処理が可能となる。


 上記のような注意点を念頭に,以下に認証の実際を書いていこう。

(1) certbot(クライアントソフト)のインストール
 まずは web サーバーに Let's Encrypt の認証用アプリケーション(クライアントソフト)をインストールしないといけない。
2017年3月の時点では,クライアントソフトの名称は「certbot」あるいは「certbot-auto」である。 以前は「letsencrypt-auto」という名前だったらしい。
 FreeBSD なら以下の ports からインストールできる。
/usr/ports/security/py-certbot/
(2020年1月現在は,/usr/ports/security/py-certbot-apacheや /usr/ports/security/py-certbot-nginx が追加で必要みたい)

 ちなみに,コマンド名だが,OS 標準のパッケージ管理システムからインストールした Certbot パッケージの場合は「certbot」コマンドを使い, 手動でインストールした場合は「certbot-auto」コマンドになるらしい。 統一しとけばいいのなぁ…。

 とりあえず,インストールしたら certbot(certbot-auto)を実行してみよう。 以下が実行結果だが,オプション指定しろと言われている。まぁ,当然か。
# certbot
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Certbot doesn't know how to automatically configure the web server on this system. 
However, it can still get a certificate for you. Please run "certbot certonly" to do so. 
You'll need to manually configure your web server to use the resulting certificate.


(2) 認証取得のテスト
 クライアントソフトのインストールができれば,まずは認証取得のテストをしてみよう。
これは上記にあるように,一週間当りに取得できる認証に制限があるため,何度もエラーを起こして制限を越えることがないようにするためである。
コマンドは以下のようなものになる。
# certbot certonly --dry-run --standalone --preferred-challenges http-01 -w /usr/local/www/data -d www.hogehoge.mydns.jp -m email@address.com
 まず,「certbot certonly」で「SSL/TLS サーバ証明書の取得のみ」を行っている。 別のオプションだと,apache の設定を勝手に書き換えるような場合もあるらしいが,ここでは「standalone プラグイン」を使って認証プロセスだけを実行させている。
 「--dry-run」は「テスト」を意味し,何度失敗しても問題はないみたい。
他のオプションは,
  ・「--preferred-challenges http-01」:80番ポートを優先的に使って認証にトライする。当初「--preferred-challenges tls-sni-01」として443番ポートを使用したが,いつの頃かだめと言われた。
  ・「-w /usr/local/www/data -d www.hogehoge.mydns.jp」:「/usr/local/www/data」を DocumentRoot とする「www.hogehoge.mydns.jp」というホスト名のマシンが対象
  ・「-m email@address.com」はメールアドレスの登録をしている。これにより,有効期限が近づくとメールをくれるらしい。

 上記のコマンドを実行して,うまくいくと以下のような結果が得られる(はず)。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1): acme-staging.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for www.hogehoge.mydns.jp
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /usr/local/etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /usr/local/etc/letsencrypt/csr/0000_csr-certbot.pem


(3) 実際に認証の取得に挑戦
 テストでうまくいきそうなら,実際に認証取得に挑戦してみよう。 先程のコマンドから「--dry-run」を除けば,取得コマンドになる。
# certbot certonly --standalone --preferred-challenges http-01 -w /usr/local/www/data -w /usr/local/www/data -d www.hogehoge.mydns.jp -m email@address.com

 コマンドを実行すると,2個ほど入力を求められる。 下記の青い部分が入力を求められている部分である(実際には色はついてないが…)。 1個はサービスへの同意であり,もう1個はメールアドレスをどっかに登録するけどいいか?というものみたい。 この確認作業は,一度行うと以降の認証作業等では聞かれることはない。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org

-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree
in order to register with the ACME server at
https://acme-v01.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 EFF and
our work to encrypt the web, protect its users and defend digital rights.
-------------------------------------------------------------------------------
(Y)es/(N)o:「Y」
Starting new HTTPS connection (1): supporters.eff.org

Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for www.hogehoge.mydns.jp
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /usr/local/etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /usr/local/etc/letsencrypt/csr/0000_csr-certbot.pem

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /usr/local/etc/letsencrypt/live/www.hogehoge.mydns.jp/fullchain.pem.
   Your cert will expire on 2017-06-13. 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
 この例は「うまくいった場合」である。 青く書いた「Congratulations!」が出れば認証成功である。 「Error」という字が見えれば失敗したことを意味している。

 以下にうまくいかなかった場合の例を示そう。 (ほんとはこっちが先だったのだが…) ここでは「mydns.jp」での認証が制限を越えた,と怒られている(赤い色をつけてみた)。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for www.hogehoge.mydns.jp
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /usr/local/etc/letsencrypt/keys/0001_key-certbot.pem
Creating CSR: /usr/local/etc/letsencrypt/csr/0001_csr-certbot.pem
An unexpected error occurred:
There were too many requests of a given type :: Error creating new cert :: Too many certificates already issued for: mydns.jp
Please see the logfiles in /var/log/letsencrypt for more details.

IMPORTANT NOTES:
 - If you lose your account credentials, you can recover through
   e-mails sent to email@address.com.
 - Your account credentials have been saved in your Certbot
   configuration directory at /usr/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.
 上にも書いたが,このエラーが出ると,時間を置いて何度も挑戦するか,あるいは,さっさと別のドメイン名を取得して挑戦するか,しかない。 ちなみに MyDNS.JP の場合,「xxx.mydns.jp」以外にも「xxx.server-on.net」や「xxx.pgw.jp」など10個以上の選択肢があるので,それらを検討するのも一つの手である。 ただし,「yyyyy.0j0.jp」みたいなのは,現時点では「見た目が怪しいドメイン名」なので,気をつけた方がいいかもしれない。
 あるいは,ムームードメインなどなら(ドメイン名の末尾によって大きく違うが…)比較的安く独自ドメイン名を取得できる。 例えば「xxx.tokyo」というドメイン名なら初年度は数百円,2年目からも1000円程度で確保できるらしい。 いっそのこと,独自ドメインの導入もいいかもしれない。


(4) 一つの認証に他のマシン名を追加取得
 上の方の Let's Encrypt を使う上での注意点で述べたように,1つのホスト名でドメイン認証を受けることができれば,同じドメイン上の他のマシン名を同じ証明書に付加することができる。 ホスト名の最初の部分(各コンピュータ独自の名前)以外が同じなら,最大100台まで追加が可能となっている(みたい)。
 以下にコマンドを示そう。
# certbot certonly --standalone --preferred-challenges http-011 -m email@address.com -w /usr/local/www/data -d kero.hogehoge.mydns.jp -w /usr/local/www/data -d www.hogehoge.mydns.jp --expand 
 コマンドは「初めて認証を得るコマンド」と似ている。 違いは,「--expand」が付加されていることと,複数のホスト名が書かれていることである。 「--expand」がつくと,作業としては「更新」になるため,認証数の制限にはかからないみたい。 複数のホスト名は,ここでは,
  -w /usr/local/www/data -d kero.hogehoge.mydns.jp
  -w /usr/local/www/data -d www.hogehoge.mydns.jp
という2台分の認証を要求している。 この2台分のホストは,1台のサーバーに複数のホスト名でのアクセス(バーチャルホスト)をさせたい場合なども含まれる。


(5) ドメイン認証の証明書の自動更新
 最後に,ドメイン認証の証明書の更新について書こう。 証明書は上にも書いたように90 日間という有効期限がある。 そこで更新が必要なのだが,以下のコマンドで更新できる。
# certbot renew --pre-hook "service apache24 stop" --post-hook "service apache24 start"
 ここでは「certbot renew」コマンドで更新にトライしている。 ここで「--pre-hook」と「--post-hook」とあるが,これは更新コマンド実行の前と後で実行したいコマンドである。 ここでは事前に apache を止めてから更新作業を行い,作業後に apache を起動する,と指定している。

 以下が実行結果である。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
-------------------------------------------------------------------------------
Processing /usr/local/etc/letsencrypt/renewal/www.hogehoge.mydns.jp.conf
-------------------------------------------------------------------------------
Cert not yet due for renewal

The following certs are not due for renewal yet:
  /usr/local/etc/letsencrypt/live/www.hogehoge.mydns.jp/fullchain.pem
No renewals were attempted.
No hooks were run.
 実は,この例では実際には更新は行われていない。 この「renew」コマンドでは,有効期限の1ヶ月以内にならないと更新作業は行わない。 強制的に更新をさせるオプションもあるが,通常は使わなくていいと思う。
 後は,このコマンドをシェルスクリプトにして,cron で週に1回程度実行させておけば勝手に更新作業をしてくれるはず。
(その4)vhost や ssl などの apache24 の設定に続く

0 件のコメント: