Let’s Encrypt で Web サイトを SSL に。

スポンサーリンク

 日本時間 2015/12/04 03:00 に無事、Let’s Encrypt の Public Beta が開始された。すっかり忘れていて一日経過した後になってしまったけど、今現在、無料で入手出来るサーバー証明書界隈では熱い認証局だから、サイトを https にしたいとか、MTA や MDA で SSL を安心して使いたい場合、Let’s Encrypt を使って見よう。
 そういえば HTTP/2 プロトコルも SSL 必須だから丁度良い時期なのかな。

 本記事の作業は CentOS 7 + Apache 2.4 でやっている。

Let’s Encrypt を使用する準備

 Let’s Encrypt ではサーバー証明書を取得する為のスクリプトが用意されているのでそれを使用する。
 スクリプトは git で clone する形でダウンロードを行う。実行には必要パッケージが自動で yum を用いたインストールで行われる。
 その為、リポジトリには epel が有効となっている必要もあるので、存在しないなら入れておく。

sudo yum install epel-release

スクリプトのダウンロード

 サーバー証明書を取得作業を行う一般ユーザーホームディレクトリで git clone を行った。

git clone https://github.com/letsencrypt/letsencrypt

 するとカレントに letsencrypt とディレクトリが作成される。

スクリプトの準備作業

 clone したスクリプトがあるディレクトリへ移動する。

cd letsencrypt/

 使用するスクリプトは letsencrypt-auto になる。何から何まで自動で処理してくれるスクリプトだ。
 取り敢えず初回は必要パッケージのインストール、スクリプト自体のアップデートチェックが行われるからヘルプを表示させるコマンドを用いて処理をさせる。

./letsencrypt-auto --help

 これにより必要パッケージとして、うちのホストでは次の 5 つが yum 経由で自動インストールされた。

Dec 04 23:36:49 Installed: python-devel-2.7.5-18.el7_1.1.x86_64
Dec 04 23:36:49 Installed: python-virtualenv-1.10.1-2.el7.noarch
Dec 04 23:36:52 Installed: dialog-1.2-4.20130523.el7.x86_64
Dec 04 23:36:52 Installed: augeas-libs-1.1.0-17.el7.x86_64
Dec 04 23:36:53 Installed: libffi-devel-3.0.13-11.el7.x86_64

 事前処理が正常終了して letsencrypt-auto –help が実行されると、ヘルプが表示されるのでそれを以て正常終了としておく。

サーバー証明書の取得

 ドメイン認証型のサーバー証明書だからドメインを認証する必要があるが、その為には DNS で引いたアドレスの Port 80 に対してアクセスを行う事で認証が行われる。よって、一旦 Apache を停止させる必要が有る。一時的に letsencrypt-auto が Listen しているのだろう。

sudo systemctl stop httpd

 ここでサーバー証明書を使用したいドメイン名を example.com に置き換えて記述すると次のようなコマンドを打ち込む。
 CentOS 7 + Apache 2.4 では、まだ証明書の設定まで一括して行うには未対応だから、証明書の取得だけに留めること。

./letsencrypt-auto certonly --standalone -d example.com -d www.example.com

 これは www にドメイン名のみのアドレスをバインドした場合であり、一つのホスト名だけでも問題は無い。
 途中、メールアドレスを入力する必要があるが、適当なアドレスを入れても良いしきっちりと hostmaster@~ や管理者らしい物を入れるのも良い。
 サーバー証明書が完成すると /etc/letsencrypt/live/example.com/ 以下に次の様に証明書が作成される。

cert.pem -> ../../archive/example.com/cert1.pem
chain.pem -> ../../archive/example.com/chain1.pem
fullchain.pem -> ../../archive/example.com/fullchain1.pem
privkey.pem -> ../../archive/example.com/privkey1.pem

 上から順に サーバー証明書、中間証明書、サーバー証明書の後に中間証明書を繋げた物、秘密鍵になっている。
 ナンバリングされた証明書に対してソフトリンクが張られているが、これは証明書を更新した際に元のファイル名が変更されてもリンクを使用していれば設定ファイルに記述するファイル名の変更まで行わなくても良くなる処置だからこのまま使うことにする。

サーバー証明書の設定記述

 /etc/httpd/conf.d/ssl.conf 若しくは自分なりに設定しているファイルへサーバー証明書の設定を行う。

SSLEngine on
SSLCertificateFile	/etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile	/etc/letsencrypt/live/example.com/privkey.pem
SSLCACertificateFile	/etc/letsencrypt/live/example.com/fullchain.pem

 この様な設定で動作する。その他細かいパラメーターは Generate Mozilla Security Recommended Web Server Configuration Files などを用いて行うと良いだろう。

動作確認

 設定を終えたら Apache を開始する。

sudo systemctl start httpd

 設定したホストへブラウザからアクセスを行う。もちろん https:// を付けるので TCP/443 を開けておく事も忘れずに。

 ブラウザからの確認であれば鍵マークをクリックしてみたりする。
15_keymark
 サーバー上で直接確認を行うなら次のコマンドを打ち込んでみる。出力例は当ホスト。SNI を用いているので -servername を教えている。

$ openssl s_client -connect example.com:443 -servername example.com -showcerts
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X1
verify return:1
depth=0 CN = bucci.bp7.org
verify return:1
以下ずらずらっと

 SSL Server Test によるチェックは A+ を獲得。
15_SSLCheck

その他注意事項

 Let’s Encrypt で取得出来るサーバー証明書の有効期限が取得日より 90 日しかない。そういう思想だそうで。
 現状は letsencrypt-auto スクリプトには未実装だが、証明書取得時のコマンドで更新が出来るようになるそうなので、自分で適当に sh で cron 回してしまえば良い物だと思われる。

参考サイト

 次のサイトを参考にした。
 Let’s Encrypt – How It Works
 Let’s Encrypt 総合ポータル

おまけ的な

 Dovecot で使用する場合、次を local.conf 等に追記

ssl = required
ssl_cert = </etc/letsencrypt/live/example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/example.com/privkey.pem

 Postfix で使用する場合、次を main.cf に記述

smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache

以下 2015/12/10 追記

サーバーを止めずに証明書の作成/更新をする

 初見では一番シンプルなサーバーを停止させた作業を行ったが、少し調べているうちに停止させずとも証明書を取得する為のドメイン認証が出来た。
 次のような引数を与えて実行する。

cd ~/letsencrypt
./letsencrypt-auto certonly --webroot -w /path/to/documentroot -d example.com

 こうすることで letsencrypt-auto が DocumentRoot 以下に .well-known/acme-challenge/ というディレクトリを作成し、更にそこへチャレンジコードになるファイルが作成される。

cd ~/letsencrypt
./letsencrypt-auto --renew-by-default certonly --webroot -w /path/to/documentroot -d example.com

 チャレンジコードファイルへのアクセスが Port 80 からアクセス出来る様であれば -d example.com に示したホスト名への認証が完了する。
 証明書の更新には最初の引数として –renew-by-default を付加すれば余計な入力確認等無しに以前設定した通りに処理をしてくれる。自動で新しい証明書が保存され、リンクも張り直されるから細かい作業は要らない。
 注意点としては mod_rewrite などのアクセス制御で、ドットファイルへのアクセスを制限するだとかしていると正常に完了しない場合もある。上手く動作しない場合にはそのへんを見なおしてみると良い。
 具体的には OwnCloud というオンラインストレージソフトなら .htaccess への追記が 1 行必要だった。

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  RewriteRule ^\.well-known/host-meta /public.php?service=host-meta [QSA,L]
  RewriteRule ^\.well-known/host-meta\.json /public.php?service=host-meta-json [QSA,L]
  RewriteRule ^\.well-known/carddav /remote.php/carddav/ [R=301,L]
  RewriteRule ^\.well-known/caldav /remote.php/caldav/ [R=301,L]
  RewriteRule ^apps/calendar/caldav\.php remote.php/caldav/ [QSA,L]
  RewriteRule ^apps/contacts/carddav\.php remote.php/carddav/ [QSA,L]
  RewriteRule ^remote/(.*) remote.php [QSA,L]
  RewriteRule ^(build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
  RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*
  RewriteRule ^(\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]
</IfModule>

 ということで、実際に cron で証明書の更新を回す時には –webroot を用いたサーバーを止めない更新が良さそうだ。ホスト名と DocumentRoot の一覧を作っておいてスクリプトで回してしまえば楽出来そう。

2015/12/13 追記
 Let’s Encrypt で取得した証明書の更新スクリプトを書いてみた

スポンサーリンク