letsencryptでSSLサーバ証明書を取得&自動更新する。

一昔前(2010年ぐらい?)までは、SSLを利用したWebサイトでは名前ベースバーチャルホストが利用できないのが常識で、次のいずれかの方法を採用するのが一般的だったと認識している。

  • HTTPSのサイトの数だけグローバルIPアドレスを用意する
  • ワイルドカードSSLサーバ証明書を使用する

前者の場合、ISPなりレンタルサーバ業者から固定グローバルIPアドレスを払い出してもらうことは可能ではあるものの、IPアドレス1個あたり月々1,000円以上かかったり、払い出してもらえる個数に制限があったりして、個人レベルであまりたくさんのSSL利用サイトを運用するのは現実的ではなかった。
後者の場合、コモンネーム(CN)のサブドメイン部分にワイルドカード(*)を指定したSSL証明書を使用することで上位ドメインが同じであれば複数のSSLサイトを利用できるので、グローバルIPアドレスを複数使わなくてもよくなった。
当サイトはSSLサイトとしては公開していないが、自宅ネットワークではメールサーバやネットワーク機器のWeb管理画面にプライベートCAで発行したワイルドカードSSLサーバ証明書を仕込んで運用しているので、十分にその恩恵を受けていると思う。
仮に公開サイトに使用するにしても、今ではSSLサーバ証明書の価格がかなり低減されており、通常のドメイン認証SSLサーバ証明書で年間1,000円ちょっと、ワイルドカードSSLサーバ証明書でも年間10,000円ぐらいで運用が可能な時代となっている。
(比較的安価なSSLサーバ証明書としてはかつてGeoTrust系のRapidSSL、COMODO系のPositiveSSLが有名どころだったが、さらに安い勢力としてCOMODO系CoreSSLなんかも出てきている模様)

いつぞやから正規のCAが悪質サイトのSSLサーバ証明書を発行してしまう事件が起こりはじめて以降、ドメイン認証だけでは認証が弱いということで組織の実在証明やより厳しい審査を経て発行されるEV(Extended Validation) SSLサーバ証明書が登場した。
それによってドメイン認証のみのSSLサーバ証明書の価値が落ちたことによるものかと思うが、無料で正規のSSLサーバ証明書を発行するStartComのようなサービスも登場し、個人がお金をかけずに正規のSSLサーバ証明書を用いたサイトを構築できるようになった。
ただ、さすがに無料なだけあって証明書の期限が1年ぐらいだったり、ワイルドカードSSLサーバ証明書は無償のものがなかったりして、僕も利用を検討したことがあったものの利便性の面で採用には至っていなかった。

そんな中で、2015年にいろいろな有名企業がスポンサーとなったサービスLet’s Encryptがβテストを開始した。
今のところ(2016年1月現在、パブリックβ中なので将来は仕様が変わるかもしれないが)証明書の期限はたった90日ではあるのだが、Webサーバでコマンドを打つだけで同じ属性情報を持つ正規のSSLサーバ証明書を何度でも容易に発行でき、cronなどを使えばSSLサーバ証明書の更新作業を自動化できる。
さらに、このサービスの方針としてワイルドカードSSLサーバ証明書を提供しない代わりにTLSの拡張仕様であるSAN(Server Alternative Names)に対応しており、コモンネームの別名(上位ドメインも違っていても大丈夫な模様)をたくさんつければワイルドカードSSLサーバ証明書よりも応用がきく。
ちょうどとある用途でWebサーバ・メールサーバを立てることになり、インターネット公開が必要だったのでSSL/TLSで暗号化したいがお金はなるべくかけたくない、SSLサーバ証明書の運用は楽がしたい、と思っていたところだったので、せっかくの機会だし試してみようと思い立った。

ここまでで前置きが長くなったが、Let’s Encryptを利用する上ではよくできた日本語リソースが存在しているので、おおよそはそれに従えばよい。
ただ、僕の環境では何か所か問題が生じたところがあったのでメモしておく。
前提として、利用した環境はUbuntu 14.04 LTS、WebサーバはApache 2.4.7だった。

Linuxのディストリビューションによってはすでにパッケージができているものもあるようだが、Ubuntu 14.04 LTSではまだ標準パッケージとしては存在していなかったため、上記のリソースに従ってgitでプログラム一式をクローンした。
その後letsencryptコマンドを実行できるようにPythonのvirtualenv環境を構築する手順に進むのだが、ここで以下のようなエラーが発生して先に進むことができなくなった。

Updating letsencrypt and virtual environment dependencies...../home/user/.local/share/letsencrypt/local/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning31.
InsecurePlatformWarning

Let’s Encryptのコミュニティの投稿によると、Pythonのバージョンが古い場合に起きる問題のようで、Pythonのバージョンを上げるかインストールするライブラリを追加すると解決するとのことだった。
Ubuntu システム全体への影響を考えるとPythonのバージョンアップは危険な可能性があると判断し、インストールするライブラリを追加する路を選択した。
スクリプト letsencrypt-auto の所定の行(僕がやったときは179行目と191行目だったが、将来変わる可能性がある)に以下の記述を追記することで問題は解決した。

VENV_BIN/pip install -U pyopenssl ndg-httpsclient pyasn1

letsencryptコマンドのヘルプが出力されるようになれば、以下の環境条件を満たしていれば問題なくSSLサーバ証明書の発行が行えた。

  • 管理者権限を持つユーザでコマンドを実行している。
  • サーバがインターネットに公開されており、letsencryptコマンド実行時に指定したFQDN(CNおよびSNI)宛にインターネットからHTTP(TCP80番)でのアクセスが可能である(DNSが適切に設定されており、ファイアウォールなどでアクセス許可されている)。
  • 事前にWebサーバを一時停止させている、またはWebrootプラグインを使ってドメイン認証用コンテンツがWebサーバのドキュメントルートに配置されている。

Let’s Encryptサービスがインターネット上のどこかからドメイン認証用コンテンツへのアクセスを試み、成功すればドメイン認証が成立する仕組みになっているようだ。

SSLサーバ証明書を利用する流れ自体は一般的な方法と変わらない。
特別なのは、letsencryptコマンドで生成されるSSLサーバ証明書、秘密鍵、中間証明書は何度更新してもシンボリックリンクを使って以下のパスに同じ名前でアクセスできるようになっているので、SSLサーバ証明書を利用するApacheなどの設定で1度パスを指定しておけば、letsencryptの再実行とデーモンの再起動(設定再読込でもよさそう)を行うことでSSLサーバ証明書の更新が可能となっている。

/etc/letsencrypt/archive/<CN (FQDN)>/

僕の場合はひとつのCNとひとつのSNIを設定したSSLサーバ証明書を作成し、Apache、Postfix、Dovecotで使用しているので、以下のコマンドをcronを使って月次で実行することにした。

#!/bin/sh

/path/to/letsencrypt-auto certonly --webroot -w /var/www/html -d <CN (FQDN)> -d <SNI> --renew-by-default

service apache2 reload
service postfix reload
restart dovecot

exit

以下のパスにはletsencryptコマンド実行時のパラメータが自動保存されているようなのだが、更新の際にそこのパラメータを読んでくれることはせず、初回発行時に指定したものと同じパラメータを指定する必要があるようだった。
1度書いてcronに仕込んでしまえばそんなに面倒なことでもないのだが、どうせならパラメータも省略して実行できた方がきれいな気がする。
まあ、今後の仕様変更でそうなる可能性はあるかもしれない。


投稿日

カテゴリー:

, , ,

投稿者:

タグ:

コメント

コメントを残す