常時SSLはもはや現代の常識!?
今を遡ること3年前、2014年のことになりますが、GoogleがSSL化されたサイトをサーチエンジンがポジティブに評価することを発表して以来、新しくWebサービスを作る場合にはSSL化することが必須タスクの一つになってきました。
私が運営するWebサービスでは、今年2017年に立ち上げたSCDB JAPANはサービス開始当時から常時SSL化の対応を行っていますが、2014年から運営している上場企業サーチ.comはユーザが情報を登録する機能を実装していないこともあり、これまでSSL対応が出来ていませんでした。
Let's Encryptの登場
従来、WebサイトのSSL化を実現するためには、認証局に対してお金を払ってサーバ証明書を発行してもらう必要がありました。 このコストは最も安いものでも年間数千円必要であり、個人が格安のレンタルサーバで運営しているような小規模なWebサイトでは無視できないケースもあったのではないかと思います。 また、証明書の発行を申請するためには、サーバにOSログインして証明書署名要求(CSR( Certificate Signing Request ))を作成する必要があり、若干のハードルがありますので、対応できずにいたWebサイト運営者もいたのではないかと思います。
そんな中、2016年に登場したLet's Encryptは通信の暗号化に特化した無料のSSL証明書発行サービスです。
ドメインを認証するDV認証にしか対応しておらず、発行される証明書の有効期限が3ヶ月と短く定期的に更新手続きが必要にはなるものの、サーバのルート権限を持っている管理者であれば簡単な操作で署名済みの秘密鍵(KEY)と公開鍵(CRT)を入手することができます。
今回、上場企業サーチ.comに導入しましたので、以下ではその手順を紹介します。 OSはCentOS7.3になります。
Let's Encryptのインストール
1.epelリポジトリを有効にしてcertbotをインストールします。
sudo yum install epel-release sudo yum install certbot
2.certbotのコマンドを実行してサーバ証明書を作成する
path-to-root
にはRailsアプリのルートディレクトリを指定します。
certbot certonly --webroot -w path-to-root -d xn--vckya7nx51ik9ay55a3l3a.com
私は上記のコマンドを実行したところ、次のエラーが発生しました。
Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator webroot, Installer None Obtaining a new certificate Performing the following challenges: http-01 challenge for xn--vckya7nx51ik9ay55a3l3a.com Using the webroot path *** for all unmatched domains. Waiting for verification... Cleaning up challenges Failed authorization procedure. xn--vckya7nx51ik9ay55a3l3a.com (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://xn--vckya7nx51ik9ay55a3l3a.com/.well-known/acme-challenge/NLgdUKK3PeaxTjwbURWZYmidDjUDfoLs61aAOggMjiQ [210.140.40.129]: 404 IMPORTANT NOTES: - The following errors were reported by the server: Domain: xn--vckya7nx51ik9ay55a3l3a.com Type: unauthorized Detail: Invalid response from http://xn--vckya7nx51ik9ay55a3l3a.com/.well-known/acme-challenge/NLgdUKK3PeaxTjwbURWZYmidDjUDfoLs61aAOggMjiQ [210.140.40.129]: 404 To fix these errors, please make sure that your domain name was entered correctly and the DNS A/AAAA record(s) for that domain contain(s) the right IP address.
エラーメッセージを見る限り、サーバ直下に作成される.well-known
ディレクトリにインターネットからアクセスしようとして404エラーが出たことが問題のようです。
Let's EncryptはSSL化しようとしているサーバに作ったファイルに外部からアクセスできることをもって、実在性の確認を行っているようです。
3..well-known
へのアクセスを許可する
上場企業サーチ.comはRailsで構築しており、publicフォルダ内に置いた静的ファイル以外はunicornに渡す設定にしているのですが、
.well-known
はpublic外にあり、当然ながらルーティングも設定されていないため、設定上正しい動きとして404になります。
今回、WebサーバにはH2Oを使っていますので、h2o.confに下記の末尾2行を追加してサービスを再起動します。
"xn--vckya7nx51ik9ay55a3l3a.com:80": listen: port: 80 host: 0.0.0.0 paths: "/.well-known": file.dir: path-to-root/.well-known/
4.改めて、certbotのコマンドを実行してサーバ証明書を作成する
Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator webroot, Installer None Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org Obtaining a new certificate Performing the following challenges: http-01 challenge for xn--vckya7nx51ik9ay55a3l3a.com Using the webroot path *** for all unmatched domains. Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/xn--vckya7nx51ik9ay55a3l3a.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/xn--vckya7nx51ik9ay55a3l3a.com/privkey.pem Your cert will expire on 2018-03-12. 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
今度は上手くいきました。
fullchain.pem
が公開鍵、privkey.pem
が秘密鍵になりますので、適切な場所に保管します。
5.h2o.confにSSL接続の設定を追加する
"xn--vckya7nx51ik9ay55a3l3a.com:443": listen: port: 443 host: 0.0.0.0 ssl: certificate-file: "path-to-fullchain.pem" key-file: "path-to-privkey.pem" cipher-suite: "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4" cipher-preference: server
ポート443の設定を追加します。
certificate-file
とkey-file
には先ほど作成した公開鍵と秘密鍵のパスを指定します。
cipher-suite
とcipher-preference
はなくても動きますが、脆弱な暗号方式を使わないようにするための設定です。
設定後、h2oサービスを再起動するとSSL通信が可能となります。
6.その他
今回は詳しくは触れませんが、上記まででSSL接続ができないときは、ファイヤーウォールでインバウンド443が空いているかを確認してください。 それから、80ポート(HTTP)へのアクセスを443ポートにリダイレクトしておいた方が良いと思いますので、適宜この設定も追加してください。
7.おまけ
昔から慣れているので今でもSSLと言ってしまいますが、暗号化方式としてSSLは既に時代遅れと言われており、世の中的にはTLS通信に移行が進んでいます。
上で書いた5.のcipher-suite
のところで、頭に"!"が付いているのはそのアルゴリズムを「許可しない」ことを意味するのですが、今回の設定ではSSLを軒並み拒否しています。
冒頭で「常時SSLは世の中の常識!?」とまで書きましたが、正しくは「常時TLSは世の中の常識!?」ですね。