無償SSLサーバー証明書Let’s Encryptの普及とHTTP/2および常時SSL化

 Webサイトの暗号化(SSL化、HTTPS対応)はこれまでEコマースやプライバシを守る目的で部分的に導入されてきたが、SHA1からSHA2への切り替え、モバイル端末の普及やHTTP/2の登場によって、サイト全体を常にHTTPS通信にする常時SSL化の動きが活発になっている。さらにSSLサーバー証明書を無償で入手可能なLet's Encryptのサービス開始や主要なWebサーバーソフトウェアの安定版でHTTP/2が利用できるようになったことでその動きは加速している。本稿ではSSL化を取り巻く最近の状況を整理し、NginxとLet's EncryptによるHTTP/2&SSL化の実装例も紹介していく。

これまで証明書の無償入手は限定的

 HTTPSのWebサイトを運用するには通常、商用の認証局にSSLサーバー証明書の発行を申し込み、必ず費用が発生するものだった。一部限定した目的では無償で利用できるものが用意されており、サーバーホスティング事業者と認証局との提携(サーバー利用費用に同梱される形など)で証明書費用が実質かからないサービスのほか、GMOグローバルサインが2013年から行っていたオープンソースプロジェクト向けのプログラムなどがあるぐらいだった。

https://jp.globalsign.com/information/news_press/2013/06/462.html

 従来はこのような認識だったと思うが、Let's Encryptのサービス開始に伴い状況が変わってきている。

無償で証明書を運用できるLet's Encrypt

 Let's Encrypt(https://letsencrypt.org/)とは、ネットワーク・サーバーベンダーなどがスポンサーとなり、無償で証明書が利用可能な認証局である。Linux FoundationのCollaborative Projectsにもなっている。このプロジェクトの活動は2012年ころから開始されていたが、2015年末からパブリックベータとして一般利用可能になり、2016年4月12日から正式に運用を開始した。

https://letsencrypt.org/2016/04/12/leaving-beta-new-sponsors.html

 Let's Encryptによる証明書の発行枚数は既存の商用認証局による発行枚数を凌駕するスピードで増え続けており、2015年末のベータ公開から2か月もしないうちに既存の主要認証局と同規模の発行枚数となり、2016年4月12日の正式運用開始時点で約170万枚、約380万ものサイトで運用されていると報告されている。

 その後もさらに増え続け、2016年6月には全世界で400万枚を超える証明書発行枚数となっている。

図1 Let's Encryptの証明書発行枚数の推移(2016年6月1日時点のグラフ)
図1 Let's Encryptの証明書発行枚数の推移(2016年6月1日時点のグラフ)

 実際にはテストで証明書だけ取得してサイト設定はまだというところも相当数あると考えられるが、多くのサイトで利用され始めているのは間違いないだろう。

 無償で証明書が入手できるとはいえ、この急激な普及の背景には、世界的に常時SSL化・HTTPS対応が進んでいることがある。Let's Encryptによる証明書発行数の推移はリアルタイムに以下のページで確認できるので、一度ご覧いただくと面白い。

https://letsencrypt.org/stats/

 このページではTLD(トップレベルドメイン)ごとの発行枚数も確認でき、とくにドイツやイギリスのユーザーでの利用が先んじて進んでいる傾向がわかる。

SSLサーバー証明書は3種類ある

 証明書を取り扱ううえで1つ押さえておきたいのは、Let's Encryptが対応するSSLサーバー証明書はDA(ドメイン認証)のみというところである。SSLサーバー証明書といっても以下のように認証の厳密さによって3段階存在することを把握しておきたい。

  • DV(Domain Validated) ⇒ ドメイン認証
  • OV(Organization Validation) ⇒ +企業(組織)の存在確認と申請者確認
  • EV(Extended Validation) ⇒ +より厳密な企業(組織)確認と申請者・署名権限者確認

 上から順に審査内容が厳密になっていき、DVは電子的な手続きのみで入手でき費用も安価である。EVは手続きが多く費用も高価だが、その分証明内容の信頼性も高い。

 これら機能的な違いをまとめると以下のようになる。

証明書の種類通信の暗号化組織の正当性利用者からの視認性
DV×○(鍵マーク)
OV○(鍵マーク)
EV◎(緑系のバー)

 どの証明書でも通信の暗号化における機能は同等で、HTTPS(通信の暗号化)だけが目的であればDVで十分である。

 OVの利用場面としては、「EVを使うほどには費用はかけられないが、組織のなりすましサイトの登場に備え、ユーザーへの説明や確認の手段を最低限用意しておきたい」という向きになるだろう。これは一般に使われているWebブラウザではDVとOVの違いを簡単に確認できないためである。今後どのように変わるかはわからないが、実用上OVによって組織が証明されているかどうかを確認するには、その通信で使われている証明書の詳細情報を見て、詳細情報中にある証明書情報を理解できる程度の知識が必要になる。一方、EVならブラウザのURL欄が緑色のバーに変更され、一般利用者には一目で厳密に認証されているサイトだとわかるようになっている。

図2 EVの証明書ではアドレスバー部分が緑色になる
図2 EVの証明書ではアドレスバー部分が緑色になる

コラム 商用の認証局から見た無償のLet's Encrypt

無償で証明書が利用できるLet's Encryptの登場は、商用の認証局にとってどのような存在だろうか? また、証明書導入のユーザー動向はどのような状態だろうか? GMOグローバルサイン プロダクトマーケティング部の近藤氏にお話しを伺った。

近藤秀樹氏
GMOグローバルサイン
プロダクトマーケティング部
マネージャー
近藤秀樹氏

認証局側から見て、証明書の導入するユーザーの変化はありますでしょうか?

 とくに最近、SSLを導入しようという気運が上がってきていると感じています。以前は一部のユーザーさんが仕方なく導入する形でしたが、『導入しなければならない』から『導入したい』という風潮に変化していると感じます。SSLの導入にはいくつかの波がありまして、最初はオンラインショップのサイトにおいて、クレジットカード情報の入力を暗号化しなければならないという考えで導入が進みました。次は2005年に施行された個人情報保護法です。ユーザー情報のやり取りを保護しなければならないという動きです。そして第三の波といいますかここ最近はモバイル端末利用の広がりから、モバイルのセッションを守る目的などで常時SSL化が活発になっています。Wi-Fiの利用が増え、無線のセッションがハッキングされることが起きていることが要因の1つだと思いますし、入力部分だけでなくトップページから信頼性をアピールすることで差別化を図りたいという向きもあります。

常時SSL化を牽引している要素には何がありますでしょうか?

 営業現場からはGoogle検索で有利になるSEO目的で導入されるユーザーさんがいるという話も聞いています。Googleが公式に検索順位の評価でHTTPSサイトを優遇すると表明したためです。そして常時SSL化が活発になった背景には、証明書のSHA2対応が必須になったことも大きな要因としてあります。ビジネスの現場ではSHA2に対応していないWindows XPの端末や古いモバイル端末もサポートしなければならず、SHA2が前提のEV証明書などを導入したくても動くに動けないという状況でした。それがSHA2の必須化で堂々とWindows XPの端末などを切り捨てることができ、同時にシステム全体を更新する気運が高まっています。

証明書の導入にあったって障害になっていた要素を挙げるとしたら何になりますでしょうか?

 まず挙げられるのはそもそもSSLが使えなかったケースがあったことです。IPアドレスが独立していない共有のホスティングサービスなどでは、技術的にSSLの導入が不可能でした。これはSNI※1によって解決しましたので今後は変わっていくと思います。そして安価になっているホスティング利用費用との落差です。サーバー利用が月額数百円台のサービスもありますので、そういった安価なサービスと比べてしまうとEV証明書の費用などはかなり高価です。正直なところ、ユーザーさんからは不満に近い声を聴くこともあります。もう1つが導入の煩雑さです。OVやEVの証明書では電話でのやり取りや書類の提出などがありますので、導入するまで数日、場合によっては数週間かかります。DVの証明書でも設定も含めると簡単に導入できるものとはいえないと思います。現在はSNIも利用できるようになったことで、ホスティングサービス事業者と連携してワンクリックでDV証明書を導入できるサービスを構築して敷居を下げているところです。

無償のLet's Encryptの登場は既存の認証局に影響がありましたでしょうか?

 安さをウリにしていた認証局は厳しくなってくだろうと思いますが、弊社ではとくに影響はありません。証明書の枚数はもちろんですが、ユーザー数は増え続けており、英国の第三者機関Netcraft社のSSL調査によると国内シェアでは弊社がトップを保っています。弊社販売の証明書の内訳を見ますと、Let's Encryptの登場以前からDV証明書の取り扱いは半数以上ですが、DV証明書で無償のサービスが普及していっても弊社のユーザーが減るということはなく、DV証明書の売上も減少はしていません。むしろ常時SSLが促進され証明書利用が当たり前になることで、OVやEVの証明書を利用するユーザーさんがさらに増えていくと考えています。

商用の認証局とLet's Encryptの違いを挙げるとしたらどのような点がありますか?

 わかりやすいところですと、日本語対応や電話でのお客様サポート、マニュアルページでの解説などです。CSR生成やサーバーへのインストールなど、初めての方には少々複雑な作業ですし、更新時も年1回の頻度のため忘れてしまっているお客様も多いです。困ったときに参照できるウェブページや、電話ですぐにご質問いただけるところが弊社SSLをご利用いただくメリットだと思います。また信頼性が重要視されるサイトでは「組織が証明されていません」と掲示されてしまうDV証明書を使うことはできれば避けたいところだと思います。DV証明書を使う場合でも証明書シールの有無があります。認証局のブランドによって信頼性をアピールしたい場合は弊社のような認証局の証明書を利用することになります。見えにくいところでは、証明書の管理コストをいかに削減できるかがビジネスの現場では一番の重要なポイントになっていると思います。証明書の有効期限をできるだけ長くしておきたい、複数の証明書を扱う場面で管理がしやすいツールが用意されているかなど、管理面を重要視しているユーザーは多いと思います。

常時SSLとは? なぜ常時SSL?

 Webサイトの通信においてユーザーの入力部分だけHTTPS通信にするということはよく行われてきたが、最近はすべてのページのアクセスをHTTPSにする常時SSL化が活発になっている。一般的な実装イメージは下図のようになる。

図3 常時SSL化の実装イメージ
図3 常時SSL化の実装イメージ

 これまでHTTPで運用してきたサイトは常時SSL化に伴い、既存のHTTPアクセスがあった場合はHTTPSのURLへ誘導する。この際、旧来のHTTPサイトが移動したとわかるように301リダイレクトを設定する。また、HTTPSアクセスのほうでは一度アクセスがあった際に次回からHTTPへのアクセスが行われないようにHSTS(HTTP Strict Transport Security)のヘッダーも加えておくのが良い。

 常時SSL化の背景には公衆無線LANなどのWi-Fi接続においてクッキーの盗聴リスクを防ぐなどセキュリティ強化の面もあるが、能動的なメリットして挙げられるのは、SEOとリファラ解析の2点になるだろう。

検索結果の順位でHTTPSサイトは有利

 国内の検索サイトで大きなシェアを持っているのはGoogleとYahoo! Japanである。Yahoo! JapanはGoogleの検索エンジンを利用しているため、国内では実質的にはGoogleの検索エンジンにおいて高評価を得られれば良い。そのGoogleの検索エンジンのアルゴリズムにおいて、HTTPSのサイトを高く評価していると、Googleからブログやセミナーなどで言及されている。

https://webmasters.googleblog.com/2015/12/indexing-https-pages-by-default.html など

 検索結果に表示されている要素のクリック率(CTR)を単純化したモデルは以下のようになる。

検索結果CTR
1番目20%超
2番目10%
3番目5%
広告0.1%のオーダー

 検索順位が下がるごとに流入数がおよそ半数に減り、順位が1つ変わるだけでユーザー流入が大きく変化してしまう。また、通常の検索結果と比べると広告のクリック率は桁違である。このように検索サイトからユーザーを獲得しようとしたとき、検索結果の上位に表示されることは非常に重要な要素であり、対策として常時SSL化が有効なものとなっている。

ユーザー動向を把握するにはHTTPSサイトにする

 常時SSL化を促進しているもう1つの要素がリファラ解析である。従来は自分のサイトに来たユーザーがどのサイトから来たか、検索サイトから来た場合はどのようなキーワードを検索して訪れたのか、リファラのアクセス解析で集計することが可能だった。しかし、自分のサイトがHTTPのサイトで流入元がHTTPSサイトの場合、リファラのヘッダーは送出されない。

アクセス元アクセス先リファラ
HTTPSHTTPSあり
HTTPSHTTPなし
HTTPHTTPSあり
HTTPHTTPあり

 主要な集客導線であるGoogleに続いて、Yahoo! Japanでも2015年8月から検索サイトにおいて、2016年4月から2017年3月にかけてサービス全体を常時SSL化する方針が発表されている。ほかのサイトでもHTTPS対応が進んでいるため、アクセス解析を行いたいと思ったら自サイトの常時SSL化はしておきたいところである。


HTTP/2対応+常時SSL化でレスポンスを向上

 次世代WebサイトプロトコルのHTTP/2も常時SSL化に関連したキーワードの1つである。HTTP/2の仕様自体はSSL化を必須としていないが、SSLを想定して整備されている面があり、実運用上はHTTP/2への移行=常時SSL化となる。

 HTTP/2の特徴の1つは、HTTPに比べて無駄な通信パケットを極力減らしていることである。とくにサイト接続からの複数ファイルの読み込みで効果を発揮し、画像が一定数存在する一般的なサイトでは、HTTPのサイトをHTTP/2に変更するだけでレスポンスが向上する。HTTP/2のデモページ(https://http2.akamai.com/demoなど)でレスポンスが良くなるところを比較してみるとわかりやすい。

図4 HTTP/2のデモページ
図4 HTTP/2のデモページ

 SSL化の懸念点としてCPU負荷が増えることによるレスポンス低下があったが、サーバーのCPU性能が向上して大きな問題にはなりにくくなっているほか、HTTP/2化も同時に行うことでWebサイト全体のレスポンス向上も実現しやすい。

 加えて、代表的なWebサーバーソフトウェアであるApacheとNginxでは安定版のバージョンでもHTTP/2対応がすでに完了した状況である。

  • 2015年10月 Apache 2.4.17以降
  • 2016年4月 Nginx 1.10.0以降

 OSやLinuxディストリビューションによっては標準で提供されるものがこれらより古いバージョンとなっているケースもあるが、それぞれ安定版で準備が整ったことで、今後常時SSL化したHTTP/2サイトもどんどん増えていくだろう。

Google ChromeでのHTTP/2対応にはOpenSSL 1.0.2以降が必要

 Google ChromeでのHTTP/2の利用にあたっては1つ注意点があるので補足しておこう。

 HTTPSでの接続の際、HTTP/1.1とHTTP/2のどちらのプロトコルを使用するかブラウザとサーバーとで合意を取る必要があり、その方式としてNPN(Next Protocol Negotiation) もしくは ALPN(Application Layer Protocol Negotiation)が使われている。これまでGoogle Chromeでは両方の方式をサポートしていたが、2016年5月末のバージョンでNPNサポートが削除され、現在はALPNを利用する必要がある。ALPNが利用できるのはOpenSSL 1.0.2以降を利用したWebサーバーからであるが、一般によく利用されているLinuxディストリビューションではOpenSSL 1.0.1ベースである。そのためたとえば、Debian GNU/Linuxの最新安定版JessieにNginxオリジナル配布の最新パッケージを導入し、WebサーバーがHTTP/2に対応しても、Google ChromeではHTTP/2が選択されず、HTTP/1.1で接続してしまう。一方、Firefoxなどでは問題なくHTTP/2で接続できる。

 2016年6月からこのような問題が発生してしまっているが、OpenSSL 1.0.1のメンテナンスは2016年末で終了することにもなっているので、運用上は一過性の問題となる可能性が高い。Google ChromeでもHTTP/2に対応したい場合は、OpenSSL 1.0.2以降をベースにWebサーバーをソースからビルドしたり、開発版やテスト版からのバックポートパッケージを利用することになるが、これからHTTP/2対応サイトを運用する場合は、上記を踏まえ、しばらくの間Google Chromeのサポートを除外しておくのは手だろう。

Let's Encryptで証明書を取得する

 Let's Encryptでの基本的な利用手順をまとめると以下のようになる。

  1. Gitを導入
  2. 証明書取得ツールを導入
  3. /.well-known/のアクセス確認
  4. root権限のあるユーザーで証明書取得ツールを実行して証明書を取得
  5. 取得した証明書をWebサーバーに適切に設定する
  6. (証明書更新用のスクリプトなどをcronなどに仕掛ける)

 Let's Encryptでのドメイン認証は、Webサーバーに認証用のファイルがあるかどうかでチェックしている。

図5 証明書取得ツールの動作
図5 証明書取得ツールの動作

 ドメイン認証の際、証明書取得ツールの実行によってドキュメントルートへの動的書き込みが発生することになるので、基本的には証明書取得ツールはWebサーバー上で実行することになる(Webサーバーと証明書を取得するサーバーを分ける例については後述)。認証用ファイルが設置される場所はドキュメントルート下の/.well-known/ディレクトリである。ここにファイル名が不定の検証ファイルが置かれ、そのファイルの存在によってドメイン認証が行われる。

証明書取得ツールを導入

 Gitが利用できる環境が準備できたら、Let's Encryptの証明書取得ツールをGitHub上の公開リポジトリからクローンして取得する。ここでは/var/opt/letsencryptに配置している。

$ git clone https://github.com/certbot/certbot /var/opt/letsencrypt

 証明書取得ツールの実行にはPythonなどが必要になるが、実行の度に必要な環境が整っているかチェックされ、足りなければ自動的にインストールされるので前準備は不要だ。そのため、実行時にはOS上にソフトウェアをインストールできるroot権限が必要である。一般ユーザーから実行した場合はsudoも自動実行される。

/.well-known/のアクセス制限を確認

 証明書を取得する際、実際にそのドメインのWebサイトが稼働し、Let's EncryptのサーバーからWebサイトにアクセスできるようしておく必要があるので、あらかじめWebサイトがファイアウォールでブロックしていないか、BASIC認証でアクセスを制限していないかなどを確認しておく。Webサーバーのアクセス制限として、ドットファイル(.htaccessファイルなど)を閲覧できないようにしていることもよくある。念のため、Let's Encryptでの認証に必要な/.well-known/ディレクトリが閲覧可能か確認しておく。具体的にはドキュメントルート下に任意文字を記載した、

/.well-known/test.txt

のようなファイルを置き、実際にWebブラウザでhttp://<ドメイン名>/.well-known/test.txtをアクセスして、test.txtが閲覧できるか確認する。もし該当ファイルにアクセスできない場合は、Webサーバーの設定ファイルに以下に代表されるような「/.」に関係した設定箇所があるかもしれない。

・Apache
<Directory ~ "/\.">
<DirectoryMatch "/\.">
<LocationMatch "/\.">
RedirectMatch 403 /\.

・Nginx
location ~ /\.
if ($uri ~ "/\.") {

 設定ファイルをチェックし、/.well-known/へのアクセスを許可する設定に調整しておく。

 なお、Let's Encryptから認証ファイルをチェックする際のユーザーエージェントは、2016年6月時点で、

Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)

となっている。

証明書の取得

 証明書を取得するには、以下のコマンドを実行する。

$ ./certbot-auto certonly --webroot --agree-tos -w <ドキュメントルート> \
-m <メールアドレス> \
-d <ドメイン名>

 ドメイン名のオプションは複数記述でき、ルートドメインとwww付きのドメインの2つに対応した証明書が必要な場合は、

$ ./certbot-auto certonly --webroot --agree-tos -w <ドキュメントルート> \
-m <メールアドレス> \
-d <ルートドメイン名> -d www.<ルートドメイン名>

のように記述すれば良い。「-d」オプションの指定内容は証明書の「サブジェクトの別名」(Subject Alternative Names)の項目になる。任意のサブドメインで使えるワイルドカードには対応していないので、複数のサブドメインで利用する場合は必要なサブドメインごとに「-d」オプションを追記していく。

 上記のコマンドを実行し、無事証明書が取得できると、以下のようなメッセージが表示される。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/<ドメイン名>/fullchain.pem. Your cert
   will expire on 2016-09-18. To obtain a new or tweaked version of
   this certificate in the future, simply run certbot-auto again. To
   non-interactively renew *all* of your certificates, run
   "certbot-auto 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のメッセージ文中に記載されているように、/etc/letsencrypt/live/<ドメイン名>ディレクトリ下に、ドメインに対応した秘密鍵、中間証明書、証明書のほか、中間証明書を含んだ証明書の4ファイルが配置される。実際に必要なのは以下の2ファイルである。

privkey.pem	秘密鍵
fullchain.pem	中間証明書を含む証明書

 この2ファイルをWebサーバーに設定すればHTTPSのWebサーバーが運用できる。

NginxのSSL設定例

 証明書が無事入手できれば、一般的なSSLサーバー証明書の設定と同じである。Apacheの設定例は/etc/letsencrypt/options-ssl-apache.confにサンプルが用意されているので参照していただきたい。ここではNginxにおける一例として、共通的なSSL設定全般を/etc/nginx/conf.d/ssl.confの別ファイルで追加し、Webサーバーごとの設定(/etc/nginx/conf.d/example.com.confなど)は別ファイルに分けて記述している環境を想定する。

 まず共通的な/etc/nginx/conf.d/ssl.confは以下のようになる。

ssl_session_cache shared:SSL:30m;
ssl_session_timeout 30m;
ssl_dhparam /etc/ssl/private/dhparam.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

 NginxではSSLでの圧縮はデフォルトでOFFなので、とくに設定を記述しなくてもCRIMEアタックには対応できている(Apacheの場合は圧縮しないように設定を入れる)。ssl_session_cacheやssl_session_timeoutのキャッシュやセッションタイムアウトは運用状態によって適宜調整となる。ssl_dhparamの部分は強度の高い鍵を別途/etc/ssl/private/dhparam.pemに作成し指定しているものである。

Diffie-Hellman鍵の強化

 Diffie-Hellman鍵は2048ビット以上が推奨されているので、セキュリティ向上のために新規に作成したものを利用する。ここでは上記設定のように鍵を/etc/ssl/private/dhparam.pemに配置するものとする。

$ sudo openssl dhparam -out /etc/ssl/private/dhparam.pem 2048

 鍵生成には環境によって数分程度はかかるのでしばらく待つことになる。

Webサーバーごとの設定

 Webサーバー設定(/etc/nginx/conf.d/example.com.confのserver内の部分)では、ポート番号の設定追加(もしくは修正)と、そのドメインに対応する証明書と鍵の設定を追加する。

server {
	listen 443 ssl http2;
	:
	:
	ssl_certificate /etc/letsencrypt/live/<ドメイン名>/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/<ドメイン名>/privkey.pem;
	:
	:

 この3行がHTTP/2サーバーとしての最低限の設定になる。

HSTS対応

 ブラウザ側の仕組みによってHTTPアクセスをHTTPSに誘導するHSTSも設定しておく。基本的にはHTTPS通信において1つヘッダーを送信するだけなので、上記server内のどこかにadd_headerを1行追加するだけである。

	add_header Strict-Transport-Security "max-age=31536000" always;

 Nginxにおいては3番目の引数に「always」を入れることで、404などのエラーでもHSTSのヘッダーを送出するようになる。404エラーページでこのヘッダーを送出したくない場合は「always」を削除しておく。

 なお、HTTP接続の際にこのヘッダーを送信しても意味がない(443ポートの待ち受けをしているserver設定内にのみ記載する)。HSTSは、HTTPS接続の際に「Strict-Transport-Security」ヘッダーがあることで「次からはこちらです」という使われ方をする機能である。

SSL化の動作検証

 以上でNginxの設定は完了である。Nginxをリスタートすれば無償の証明書によるHTTPSに対応したWebサーバーの出来上がりである。

$ sudo /etc/init.d/nginx restart

 もし、うまく動作していないようなら、まずはnetstatを使い、Nginxが正しく起動しHTTPSの443ポートで待ち受けしているかを確認する。

$ sudo netstat -pantu |grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      14303/nginx.conf
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      14303/nginx.conf

 上記のようにきちんと443ポートで待ち受けをしているのにも関わらず、サイトが見えないとう場合は、iptablesなどのファイアウォールで443ポートが塞がれていないかチェックするといいだろう。

$ sudo iptables -L -n -v
	:
	:
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443
	:
	:

厳密にSSLの実装をチェックする

 共通的なSSLの設定例で示したように、証明書の設定はやや煩雑になり不安が残るところである。証明書の設定を正しく設定できたかを確認するには、以下のようなWebサービスとして用意されているSSLのチェッカーを使うのがよい。

https://globalsign.ssllabs.com/analyze.html

図6 SSLチェックツール
図6 SSLチェックツール

 上記サイトにアクセスしたら、Hostnameの入力欄にURLを記述し、「Submit」ボタンを押すとチェックが行われる。このサイトでのチェック内容は多岐にわたり、すべての検査が終わるのに数分は待つことになる。

 しばらくしてチェックが終わると総合評価とチェック項目の詳細などが表示される。

図7 診断結果
図7 A+の診断結果

 この図の結果のように「A+」と評価されるのが目標である。前述の設定であれば「A+」と評価されているだろう。もし減点になる部分があれば、問題個所が提示されているのでチェックしていく。

Let's Encryptの証明書の更新

 Let's Encryptの証明書の有効期限は90日となっており、運用にあたっては1、2か月に一度のペースで証明書の更新作業を行う必要がある。証明書の更新は証明書の取得で利用したcertbot-autoコマンドでrenewオプションを使えばよい。

$ /var/opt/letsencrypt/certbot-auto renew

 このコマンドによって、証明書取得時に/etc/letsencrypt/renewal/以下に設置されたドメインごとの設定ファイルが参照され、デフォルトでは有効期限切れ30日未満のドメインに対して更新作業が行われる。残り有効期限が長い証明書については更新作業がスキップされるようになっている。通常は有効期限を変更する必要はないだろう。

 もし、更新実行の期間を調整したい場合は、/etc/letsencrypt/renewal/以下にある<ドメイン名>.confというファイル名の設定ファイルで、以下のような設定を追加(コメントアウトを削除)して日数を変更しておく。

# renew_before_expiry = 30 days

 実運用時には自動的に証明書が更新(「certbot-auto renew」コマンドを実行)されるようにしておくことになるだろう。デフォルトの30日未満で更新するという設定なら30日未満で2回以上実行されるようにcronに設定しておく。たとえば、毎週日曜日午前2時22分に実行するcronの設定例(root)は以下のようになる。

22 2 * * 0 /var/opt/letsencrypt/certbot-auto renew >> /var/log/letsencrypt.log

 また、鍵の更新(certbot-autoの出力や取得した鍵ファイルのタイムスタンプなど)を検知してNginxを再起動させるスクリプトも用意しておいたほうが良いだろう。

更新がない場合のcertbot-autoの出力末尾
  /etc/letsencrypt/live/example.org/fullchain.pem (skipped)
  /etc/letsencrypt/live/example.com/fullchain.pem (skipped)
No renewals were attempted.

更新があった場合のcertbot-autoの出力末尾
  /etc/letsencrypt/live/example.org/fullchain.pem (skipped)
Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

 以上で、Let's Encryptを利用した基本的なWebサーバーの設定は完了である。

フロントサーバーで証明書取得ツールを動作させない構成

 Let's Encryptの証明書取得ツールは、動作のためにソフトウェアインストールを行うほか、今後のアップグレードなどで想定しない動作をする可能性もある。掌握できていないツールをフロントのWebサーバーで動作させるのは怖いので、証明書の取得は別のサーバー上で行い、改めて証明書をWebサーバーにコピーしたいという運用はあるだろう。また、とくにNginxを利用している場合、フロントのWebサーバーはキャッシュ(リバースプロキシ)として機能しており、バックエンドのAPPサーバーとの組み合わせで利用したいという場合もある。たとえば下図のようなNginxの構成である。

図8 Nginxの多段構成にて、証明書をコピーする例
図8 Nginxの多段構成にて、証明書をコピーする例

 Let's Encryptの利用でのポイントは/.well-knownを透過的に設定しておくことになる。具体的には以下のような数行を加えることによって実装は可能である。まずフロントサーバー側(/etc/nginx/conf.d/front.conf)は以下のlocation設定を追加する。

server {
	:
	:
	location ~ ^/.well-known {
		proxy_set_header Host letsencrypt;
		proxy_no_cache 1;
		proxy_cache_bypass 1;
		proxy_pass http://<鍵取得用のサーバーのIPアドレス>;
	}
	:
	:
}

 フロントとバックエンドとの通信はHTTPのままとし、proxy_passでバックエンドサーバーのIPアドレスを指定する。proxy_no_cacheとproxy_cache_bypassを1とすることにより認証用ファイルなどがキャッシュされることなく、このパスのアクセスのみ透過的にファイルが参照されるようになる。proxy_set_headerの部分は名前解決できるドメイン名である必要はなく、任意の文字列でかまわない。証明書取得後は前述のSSL関連の設定を整備していく形になる。

 続いて、バックエンド側は既存のサーバーとは独立した名前のバーチャルホストとして、以下のような記述の/etc/nginx/conf.d/letsencrypt.confを用意するだけである。

server {
  server_name letsencrypt;
  root /var/www/letsencrypt;
  access_log /var/log/nginx/letsencrypt/access.log combined;
  error_log /var/log/nginx/letsencrypt/error.log warn;
}

 server_nameとして、フロントサーバー側のproxy_set_headerと同じ文字列を指定する。なお、この設定を反映させる際は、独立のバーチャルホストとしているので、ドキュメントルートとログのディレクトリを作成してからNginxを起動(再起動)する。

$ sudo mkdir /var/www/letsencrypt /var/log/nginx/letsencrypt
$ sudo /etc/init.d/nginx restart

 このように、すでにNginxのプロキシ+APPサーバー構成で運用している場合は、フロント側に6行の追加、バックエンドに6行ほどのバーチャルホスト設定の追加だけで構成できる。なお、ここでは独立のバーチャルホストで認証を行うことにしたので、証明書取得の際は、ドキュメントルートの指定オプション「-w」に「/var/www/letsencrypt」を指定する。

$ ./certbot-auto certonly --webroot --agree-tos -w /var/www/letsencrypt \
-m <メールアドレス> \
-d <ドメイン名>

HTTP/2+常時SSLの時代へ

 SSLサーバー証明書を取り巻く状況は変わり、以前と比べてかなり利用しやすい状況にあることは把握していただけたと思う。Let's Encryptの利用も全体が見えればそれほど面倒でもない。現状はセキュリティを強化する証明書の推奨設定が整理され切っていないが、解説ドキュメントが必要ないぐらいにデフォルト設定が整うのもすぐだろう。そしてインターネット上のサイトのほとんどが常時SSLのHTTP/2となっていくのは間違いなく、かなり早いスピードで進むことが予想できる。まずは身近に管理しているサイトから常時SSL化HTTP/2化を進めてみてはいかがだろうか。