ApacheでのLet's Encrypt運用が簡単になりました
2019-07-10 Web Windows

Let’s Encrypt は無料でサーバー証明書を発行してくれる認証局です。2016 年のサービス開始以来 急速に普及しています。

Let’s Encrypt の証明書発行には ACME プロトコルに対応したクライアントソフトウェアを使います。主要な ACME クライアントソフトウェアは ACME Client Implementations で紹介されています。Let’s Encrypt のサイトでは certbot というツールが推奨されているのですが このツールは Windows には対応していません。Windows 環境では win-acme 旧名 letsencrypt-win-simple というツールが良く使われているようです。

私も これまで win-acme を使ってきたのですが 先日 ふとしたことで mod_md という Apache モジュールの存在を知りました。mod_md win-acme よりもずっと簡単に使えます。ただし mod_md Apache モジュールであるため Apache 環境でしか使えません。IIS など他のウェブサーバーに Let’s Encrypt を導入するのであれば 引き続き win-acme が有力な選択肢になります。

Apache 2.4.30 以降で利用可能になった mod_md モジュールを使って Let’s Encrypt 証明書を導入する手順を紹介していきます。

ドメイン認証

Let’s Encrypt では ドメイン認証 Domain Validation:DV 証明書を発行することができます。企業認証 Organization Validation:OV 証明書 EV Extended Validation 証明書は発行できません。

ドメイン認証について少し説明しておきましょう。OV EV では電話確認や登記確認によって組織の実在性を確認しますが DV ではドメインの所有者であることを間接的に確認します。

方法は主に 3 つあります。

メール認証
あなたが example.com ドメインの管理者なら postmaster@example.com 宛のメールを受け取れるはずです。メールで認証コードを送るので その認証コードを入力してください。それができたら example.com を所有していると認めます。
DNS 認証 dns-01
あなたが www.example.com ドメインの管理者であるなら DNS を変更できるはずです。私が指定する値を example.com TXT レコードに設定してください。私がそれを確認できたら www.example.com を所有していると認めます。
HTTP 認証 http-01
あなたが www.example.com ドメインの管理者であるならウェブサイトを変更できるはずです。私が指定するファイルを http://wwww.example.com/.well-known/~で参照できるように配置してください。私がそれを確認できたら www.example.com を所有していると認めます。

大体こんな感じです。ドメインを所有していればできることを課題として出され それを達成すればドメイン所有者として認められるということですね。

Let’s Encrypt はメール認証には対応していないので DNS 認証か HTTP 認証を使うことになります。HTTP 認証のほうが扱いやすい人が多いかな? 私の場合は お名前.com を使っているので DNS の変更には Web インターフェース ブラウザー を使う必要があります。Apache の設定で条件をクリアできる HTTP 認証のほうがやりやすいと考えました。

win-acme で面倒だったところ

HTTP 認証をするためには指定されたファイルを /.well-known/ に配置してインターネット側から参照できるようにしなければなりません。これが Apache では少し手間がかかりました。

Apache では httpd.conf SSLCertificateFile ディレクティブにサーバー証明書のファイルパスを指定するのが一般的ですが ここに存在しないファイルパスが指定されていると Apache 自体が起動できなくなります。そのため サーバー証明書を発行する前は SSLCertificateFile SSLEngine on をコメントアウトして HTTP のみが有効な状態で Apache を起動する必要がありました。

/.well-known/ が参照できるように HTTP のみの構成で Apache を起動して認証を通す その後 取得したサーバー証明書を SSLCertificateFile に指定して HTTPS 構成の Apache を起動する という 2 ステップが必要だったわけです。

途中で httpd.conf を書き換えるのがなんとなく億劫でした。これが mod_md を使うことで改善できます。

mod_md の設定

mod_md では SSLCertificateFile ディレクティブを使いません。サーバー証明書のファイルパスを明示的に指定する必要がないのです。

mod_md の設定手順を説明していきましょう。

mod_md の使用には mod_md.so だけでなく mod_watchdog.so もロードする必要があります。SSL/TLS を使うのが目的ですから mod_ssl.so mod_socache_shmcb.so もロードしておきます。

必要なモジュール(httpd.conf)
LoadModule ssl_module modules/mod_ssl.so LoadModule socache_shmcb_module modules/mod_socache_shmcb.so LoadModule watchdog_module modules/mod_watchdog.so LoadModule md_module modules/mod_md.so

次に mod_md の共通設定です。

共通設定(httpd.conf)
MDBaseServer on MDCertificateProtocol ACME MDCAChallenges http-01 MDDriveMode auto MDPrivateKeys RSA 2048 MDRenewWindow 33% MDStoreDir md MDCertificateAuthority https://acme-v01.api.letsencrypt.org/directory MDCertificateAgreement https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf

基本的には上記の設定のままで大丈夫です。それぞれのディレクティブの設定の意味は下記サイトで確認できます。

いくつかのディレクティブについて説明します。

MDStoreDir
管理対象ドメインのデータを格納するローカルファイルシステム上のパスを指定します。既定値は md です。既定値 md のままなら ${SRVROOT}/md になります。実際は C:¥Apache24/md などのパスに展開されるでしょう。
 
MDRenewWindow
証明書を更新するしきい値を指定します。既定値は 33% です。Let’s Encrypt の証明書の有効期間は 90 日です。既定値 33% のままなら残りの有効期間が 30 日になった時点で証明書が更新されます。割合ではなく日数を指定する場合は % の代わりに d を使用します。21d と指定すれば 残り 21 日で証明書が更新されます。
 
MDCertificateAuthority
認証局の証明書発行サービスの URL を指定します。既定値は https://acme-v01.api.letsencrypt.org/directory です。Let’s Encrypt 1 日に証明書発行リクエストを出せる回数に上限があります。DNS やサーバーの設定に誤りがあって何度も証明書発行に失敗してしまうと しばらく証明書が発行できなくなってしまいます。そうならないように 最初はテスト用の URL https://acme-staging.api.letsencrypt.org/directory を指定して確認をしましょう。テスト用の URL なら何度失敗しても大丈夫です。ただし テスト用の URL では正規の証明書は発行されません。代わりに Fake LE Intermediate X1 という偽物の証明書が発行されます。この証明書が発行されれば DNS httpd.conf の設定に誤りはないはずです。それを確認してから正規の URL https://acme-v01.api.letsencrypt.org/directory を設定するのが良いでしょう。
 
MDCertificateAgreement
Let’s Encrypt には利用規約があります。規約に同意せずに利用することはできません。とはいえ 画面に規約を表示して同意ボタンを押させるようなインターフェースでは自動化の妨げになってしまいます。利用者は 利用規約に同意したことを示すために 読んで同意した利用規約の URL MDCertificateAgreement に指定します。  

最後にホスト固有の設定です。

ホスト固有の設定(httpd.conf)
MDomain www.example.com <VirtualHost *:443> SSLEngine on ServerName www.example.com DocumentRoot "${SRVROOT}/htdocs" # 本来ならここで SSLCertificateFile を指定しますが mod_md では必要ありません。 # MDStoreDir で指定した場所にサーバー証明書が作成され、それが自動的に使用されます。 </VirtualHost> <VirtualHost *:80> ServerName www.example.com DocumentRoot "${SRVROOT}/htdocs" </VirtualHost>

MDomain ディレクティブに証明書を発行するドメイン名 Common Name:CN を指定します。あとは VirtualHost ディレクティブ内の ServerName に同じドメイン名を指定するだけです。

Apache を起動してみる 1 回目

まずは練習ということで httpd.conf MDCertificateAuthority にテスト用の URL https://acme-staging.api.letsencrypt.org/directory を指定しておきます。

# MDCertificateAuthority  https://acme-v01.api.letsencrypt.org/directory
# ↓
MDCertificateAuthority  https://acme-staging.api.letsencrypt.org/directory

Apache を起動すると error.log に気になる出力が記録されます。

error.log
[Sun Jun 16 21:20:06.222610 2019] [ssl:warn] [pid 3528:tid 564] AH10085: Init: www.example.com:443 will respond with '503 Service Unavailable' for now. This host is part of a Managed Domain, but no SSL certificate is available (yet). [Sun Jun 16 21:20:15.727703 2019] [md:notice] [pid 3528:tid 528] AH10059: The Managed Domain www.example.com has been setup and changes will be activated on next (graceful) server restart.

読みやすいように改行を入れました。日本語に訳すとこんな感じでしょうか。

error.log(日本語訳)
初期化: 今のところ www.example.com:443 は '503 Service Unavailable' を応答します。 このホストは管理ドメインの一部ですが、利用可能なSSL証明書が(まだ)ありません。 管理ドメイン www.example.com がセットアップされました。 変更は次回のサーバー再起動時に有効になります。

ちなみに 利用可能な SSL 証明書がありませんという警告は 4 行出力されていました。

ふむぅ。1 回の起動ではダメなようです。おそらく Let’s Encrypt の証明書発行プロセス完了前に Apache を起動させるためにこのようになっているのでしょう。

ブラウザーで https://www.example.com にアクセスしてみても やはりエラーが表示されます。

証明書を表示してみると Apache Managed Domain Fallback という証明書になっています。これは Let’s Encrypt が発行した証明書ではなく Apache 内部で生成されたダミー証明書です。ダミー証明書で代替することで ひとまず Apache が起動できる仕掛けのようです。従来の SSLCertificateFile ディレクティブを使う方法では サーバー証明書なしで HTTPS 構成の Apache を起動させることはできなかったはずです

Apache を起動してみる 2 回目

次回のサーバー再起動時に有効になるとログに出ていたのですから 素直に Apache を再起動してみましょう。

error.log
[Sun Jun 16 21:23:47.907378 2019] [ssl:warn] [pid 11084:tid 536] AH10085: Init: www.example.com:443 will respond with '503 Service Unavailable' for now. This host is part of a Managed Domain, but no SSL certificate is available (yet). [Sun Jun 16 21:23:48.032424 2019] [mpm_winnt:notice] [pid 11084:tid 536] AH00455: Apache/2.4.39 (Win64) OpenSSL/1.1.1c SVN/1.12.0 configured -- resuming normal operations [Sun Jun 16 21:23:48.032424 2019] [mpm_winnt:notice] [pid 11084:tid 536] AH00456: Server built: May 29 2019 21:57:40

no SSL certificate is available (yet). 利用可能な SSL 証明書がありません という警告がまだ出ていますね。初回は 4 行出ていたのですが 今回は 1 行しか出ていないので起動シーケンスの途中で問題が解決したのかもしれません。

ブラウザーで https://www.example.com/ を開いてみましょう。

やはりダメなのかな? 一応 証明書も確認しておきましょうか。

おおっ。さっきとは証明書が違います。発行者が Fake LE Intermediate X1 になっています。LE というのは Let's Encrypt の略ですね。これは Let’s Encrypt が発行してくれた証明書 のフェイク です。

証明書がフェイクになっているのは MDCertificateAuthority にテスト用の URL https://acme-staging.api.letsencrypt.org/directory を指定していたからです。想定通りです。

フェイクとはいえ Let’s Encrypt から証明書を取得できたわけですから DNS Apache の設定には問題なさそうです。自信が出てきました。

Apache を起動してみる 3 回目

フェイク証明書の発行が成功したので正規の証明書発行に進みましょう。

httpd.conf MDCertificateAuthority ディレクティブの値を正規のサービス URL https://acme-v01.api.letsencrypt.org/directory にします。

httpd.conf
MDCertificateAuthority https://acme-v01.api.letsencrypt.org/directory

それと フェイク証明書一式が ${SRVROOT}/md たとえば C:¥Apache24¥md など に残っているので削除しておきましょう。md フォルダーをまるごと削除してしまって大丈夫です。必要に応じて md フォルダーは再作成されます。

それでは 3 回目の Apache を起動して error.log を確認します。

error.log
[Sun Jun 16 21:40:08.529514 2019] [ssl:warn] [pid 6824:tid 564] AH10085: Init: www.example.com:443 will respond with '503 Service Unavailable' for now. This host is part of a Managed Domain, but no SSL certificate is available (yet). [Sun Jun 16 21:40:17.415908 2019] [md:notice] [pid 6824:tid 612] AH10059: The Managed Domain www.example.com has been setup and changes will be activated on next (graceful) server restart.

初回と同じで サーバー再起動で有効になる旨のメッセージが出力されています。md フォルダーをまるごと削除して証明書が存在しない状態に戻したの当然ですね。

Apache を起動してみる 4 回目

もう一度 Apache の起動して ブラウザーで https://www.example.com/ にアクセスします。

うまくいきました! この接続は保護されています と表示されています。

証明書の発行者は Let's Encrypt Authority X3 となっています。Fake の表示はありません。

今回は テスト用の URL を指定してフェイク証明書を発行して練習しましたが DNS などネットワーク構成に問題ないことが分かっているなら 初回から正規の URL https://acme-v01.api.letsencrypt.org/directory を指定しても構いません。

Apache を再起動しないと有効にならないというのは少しモヤっとしますが 単純に再起動すればいいだけなので大した手間ではありません。win-acme のときよりもずっとシンプルになりました。嬉しいです。

この記事を共有しませんか?