Let's EncryptのSSL証明書で、安全なウェブサイトを公開

安全なウェブサイトを公開するため、無料で利用可能な Let's Encrypt の証明書を使う方法をご紹介します。Let's Encrypt の背景とSSL証明書の自動発行をはじめ、CentOS 7 上の Nginx ウェブサーバを SSL に対応する方法、そして、証明書を自動更新する方法を見ていきましょう(所要時間10~20分)。

なお、Let's Encrypt については既に中津川さんの記事「すべてのWebサイトの暗号化を目指すLet's Encryptを試す」で取り上げられていますが、今回は新しいクライアント certbot-auto を使う方法や、証明書の自動更新の仕方をとりあげます。

こんにちは!こんにちは!

みなさん、はじめまして。さくらインターネットの前佛雅人(ぜんぶつまさひと)です。さくらのナレッジに何か書け(業務命令)ということで、皆さんがサーバをより活用できるよう、ナウでヤングにバカウケな便利情報を共有していきたいなと考えています。どうぞ、よろしくお願いいたします。

今回のお題は、安全なウェブサイト

インターネット上での通信を保護し、様々な情報を安全に保つには、SSL(Secure Sockets Layer)/TLS(Transport Layer) を使った暗号化と成りすましの防止は欠かせません。暗号化しませんと、ブラウザを通す全ての通信がインターネット上に晒されます。システムのパスワードやプライベートな情報など、他人に知られたくない情報は守りたいものです。

ですが、ウェブサーバで HTTPS 通信を有効にするには、証明書作成に手間やお金が掛かりがち。企業やショッピングサイトであれば、ある程度の予算や手間暇をかけられます。しかし個人レベルでは、なかなか敷居が高かったのが、SSL/TLS への対応ではないでしょうか。

今回紹介する証明局(CA; Certificate Authority)の Let's Encrypt を使えば、無料で SSL 用の証明書を取得できます。単に無料で使えるだけでなく、証明書の取得の簡易さと、そして、何よりも速さを兼ね備えています。いくつかの簡単なコマンドを実行するだけで、即時に証明書の取得・更新ができるのです。

もしも、安全なウェブサイトが今すぐ必要で、かつ手軽に使いたい時には、Let's Encrypt を活用してはいかがでしょう。

以降では、証明書を発行するまでの詳細な手順と、Nginx で SSL 証明書を有効にするまでの流れを見ていきましょう。

lets-encrypt-arch

Lets's Encrypt とは?

Let's Encrypt(レッツ・エンクリプト)とは SSL/TLS の暗号化通信に用いる証明書の認証局(CA; Certificate Authority)の1つです。世界中には様々な認証局がありますが、Let's Encrypt には次の特長があります。

  • 自由に使える
  • 証明書の署名は自動的
  • オープン

かつてはベータ版としてのサービス提供でしたが、2016年4月から正式サービスとして提供が始まっています。既に世界中で 200 万件の証明書を発行済みです。

どうして無償で使えるの?

Let's Encrypt の運営母体は電子フロンティア財団(EFF; Electronic Frontier Foundation)であり、1990年に設立されています。2009 年に制定された長期的なミッションが「ウェブの暗号化(Encrypting the web)」でした。安全ではない平文の HTTP 通信を、すべて暗号化した HTTPS に置き換えようという野心的な目標が掲げられたのです。

そして、Let's Encrypt Certificate Authority が立ち上がります(参考情報)。認証局の目的は、深い知識がなくても、誰もが HTTPS を扱えることを目指すため。Mozilla を始めとしたスポンサーの支援や寄付を経て、2015年9月にベータ版としてサービス提供を始めます。そして、今年4月12日から、正式サービスをリリースしました。

自動証明書発行の仕組み

Let's Encrypt の証明書発行の流れは、通常の証明書発行の流れに近いのですが、自動的に行う点がユニークです。ドメインの正当性を確保するため、外部からサーバの中にアクセス可能でなければ、証明書を発行しない仕組み(ACME プロトコル)を取り入れています。この仕組みにより、自動的かつ迅速に証明書を発行できます。

acme-protocol

一般的な証明書・認証局との違い

違いは主に2つあります。1つは、SSL/TLS サーバを提供する組織や団体が実在するかどうかの証明です。ブラウザ上で安全な通信が確保されていたとしても、その通信先のサーバが必ずしも安全かどうかは分かりません。実在する組織を騙る場合、類似している場合や実在しない可能性もあります。

その場合は、認証局や証明書で区別する必要も出てきます。証明書の種類によっては、発行のためには登記簿謄本などの公的機関が発行する情報を確認する場合もあります。

もう1つは、簡単さと速さです。こちらは繰り返しとなりますが、サイトの証明書が必要であれば、自分がコマンドを実行するだけで証明書の発行や、サーバ側の設定をできるのは便利ではないでしょうか。

事前準備と動作環境

今回、想定している環境は、さくらのクラウド上の CentOS 7.2 です。さくらの VPS、さくらの専用サーバでもほぼ同様の手順でご利用いただけます(一部の設定が異なる可能性があります)。

また、Let's Encrypt を使った HTTPS 通信用の証明書の作成には、対象のマシン上にドメイン名でアクセスできる必要があります(IP アドレスに対する証明書は作成できない仕組みです)。そのため、さくらのクラウドの DNS サーバ・アプライアンスなどで、あらかじめドメイン名の A レコード設定をお願いいたします。

CentOS に Nginx のセットアップ

さくらのクラウドで CentOS 7.2 のサーバを準備し、ウェブサーバとして Nginx をセットアップします。サーバ上で次のコマンドを実行します。

# yum install --enablerepo=epel nginx

Nginx のセットアップには EPEL リポジトリ上の nginx パッケージを使用します。さくらのクラウドでは EPEL リポジトリのパッケージ(epel-release)がセットアップ済みです。ただし、デフォルトでは有効ではありません。そのため、 yum でのセットアップ時にリポジトリを有効化する「--enablerepo epel」のオプションが必要です。

また、サーバ再起動時に自動的に Nginx を起動するには、次の systemctl コマンドを実行します。

# systemctl enable nginx

それから Nginx を起動するため「systemctl start nginx」コマンドを実行し、動作確認のため「systemcltl status nginx」コマンドを実行します。

* nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2016-07-11 18:24:30 JST; 4s ago
  Process: 14782 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 14780 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 14778 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 14785 (nginx)
   CGroup: /system.slice/nginx.service
           |-14785 nginx: master process /usr/sbin/nginx
           `-14786 nginx: worker process

Jul 11 18:24:30 secure systemd[1]: Starting The nginx HTTP and reverse proxy server...
Jul 11 18:24:30 secure nginx[14780]: nginx: the configuration file /etc/nginx/nginx.conf synt...s ok
Jul 11 18:24:30 secure nginx[14780]: nginx: configuration file /etc/nginx/nginx.conf test is ...sful
Jul 11 18:24:30 secure systemd[1]: Failed to read PID from file /run/nginx.pid: Invalid argument
Jul 11 18:24:30 secure systemd[1]: Started The nginx HTTP and reverse proxy server.
Hint: Some lines were ellipsized, use -l to show in full.

このように nginx サービスの状態が「active (running)」であれば正常に実行中です。

firewalld で外部との通信を許可

Nginx をセットアップしましたが、このままではサーバの外と Nginx は通信できません。CentOS 7 の初期状態では firewalld が有効であり、この段階では HTTP と HTTPS の通信は許可されていません。そのため、Nginx を起動してもブラウザからは見えない状態です。

CentOS 7 以降は firewalld が iptables の通信ルールを管理する役割を持ちます。次のコマンドを実行し、firewalld のコマンドライン・ツールが利用可能かどうかを確認します。

# firewall-cmd --state
running

このように「running」と表示されていれば正常です。そうではない場合は firewalld が停止している可能性があるため、systemctl status firewalld で状況を確認し、必要があれば起動や再起動等の対策・確認をします。

HTTP (Port 80/tcp) と HTTPS (Port 443/tcp) の通信を許可するには次のコマンドを実行します。

# firewall-cmd --add-service=http --permanent
success
# firewall-cmd --add-service=https --permanent
success
# firewall-cmd --reload
success

最後に「firewall-cmd --reload」コマンドを忘れずに実行します。このコマンドを実行した段階で、設定が反映できます。

あとはブラウザから「http://<ホスト名>/」にアクセスしたら、Nginx の初期画面が見えます。

nginx-default

  • Nginx が起動しているかどうか(systemctl status nginx)
  • firewalld の機能が有効かどうか(systemctl status firewalld)
  • その他、ファイアウォールなどで通信が許可されているかどうか

certbot-auto のセットアップと証明書の自動生成

「certbot-auto」は Let's Encrypt が提供しているツールであり、Let's Encrypt と通信するエージェント(クライアント)です。2016年5月より以前は letsencrbot と呼ばれていました。このツールは Let's Encrypt から証明書を取得し、サーバの HTTPS を有効化する機能があります(自動有効化はオプションで、現在 Apache のみ対応)。オープンソースのツールとして GitHub で公開・開発されており、様々なディストリビューション上で動作します。

ここでは最新版の certbot-auto を取得します。セットアップには、次のコマンドを実行します。

# curl https://dl.eff.org/certbot-auto -o /usr/bin/certbot-auto
# chmod 700 /usr/bin/certbot-auto

ダウンロードした certbo-auto はシェル・スクリプトで、証明書の操作に関する様々なコマンドを実行できます。

次は certbot-auto コマンドを使って証明書を自動生成します。書式は以下の通りです。ここでは Nginx のデフォルトのドキュメント・ルート「/usr/share/nginx/html」を指定していますが、任意の場所に変更できます。また「-d」のドメイン名、「--email」は、皆さんの環境にあわせて書き換えをお願いします。

# certbot-auto certonly \         # 証明書の作成
    --webroot \                   # 既存のウェブサーバを使うモードを選択
    -w /usr/share/nginx/html \    # ドキュメント・ルートのパス
    -d secure.zem.jp \            # 認証するドメイン名
    --email <メール>@<アドレス>     # メールアドレス登録(証明書期限切れの通知用)

このコマンドを実行したら、パッケージのセットアップが始まる場合があります。そのときは、画面の内容を確認の上、パッケージを追加セットアップするために 「y」 を入力します。

(省略)
Total download size: 9.9 M
Installed size: 25 M
Is this ok [y/d/N]: y ←入力

利用規約(Terms of Service)が表示されます。「Agree」でエンターキーを押します。

lets-encrypt-setup1

あとは自動的に certbot-auto が Let's Encrypt の認証局と通信を行い、証明書を自動生成します。このとき、firewalld で http 通信を許可していないと証明書の作成ができません。Let's Encrypt は対象ドメインの存在性を、ホスト名で正しく通信できるかどうかで判別します。もし、ファイアウォールやルータでパケットフィルタを使っている場合は、公開されているかどうかの確認が必要になります。

次のような画面が表示されれば、処理完了です。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/secure.zem.jp/fullchain.pem. Your cert will
   expire on 2016-10-09. 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 lose your account credentials, you can recover through
   e-mails sent to <メールアドレス>.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - 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

処理が終われば、証明書に関連したファイルが自動生成されています。作成したファイルは /etc/letsencript 以下のディレクトリに保存されています。

この例ではホスト名が「secure.zem.jp」のため、ホスト名の階層以下で、次のような証明書や秘密鍵などのファイルを確認できます。

# ls -l /etc/letsencrypt/live/secure.zem.jp/
total 0
lrwxrwxrwx 1 root root 37 Jul 11 18:40 cert.pem -> ../../archive/secure.zem.jp/cert1.pem
lrwxrwxrwx 1 root root 38 Jul 11 18:40 chain.pem -> ../../archive/secure.zem.jp/chain1.pem
lrwxrwxrwx 1 root root 42 Jul 11 18:40 fullchain.pem -> ../../archive/secure.zem.jp/fullchain1.pem
lrwxrwxrwx 1 root root 40 Jul 11 18:40 privkey.pem -> ../../archive/secure.zem.jp/privkey1.pem

そして、ここでは各々がシンボリック・リンクになっていることに注目します。certbot には更新(renew)機能が備わっています。これは、コマンドを実行するだけで、新しい証明書を自動生成し、このリンク先を切り替える仕組みがあります。この機能のお陰で、Nginx などサーバ側の設定ファイルのパスを変更しなくても、常に新しい証明書を利用できる便利な仕組みです。

Nginx の SSL 対応設定

あとは Nginx で生成した証明書を読み込む設定をするだけです。 新しく /etc/nginx/conf.d/ssl.conf ファイルを開き、次のように内容を追記します。証明書(ssl_sertificate)と秘密鍵(ssl_certificate_key)のパスは、皆さんの環境にあわせて書き換えをお願いします。

server {
        listen  443 ssl;
        server_name     secure.zem.jp;
        ssl_certificate         /etc/letsencrypt/live/secure.zem.jp/cert.pem;
        ssl_certificate_key     /etc/letsencrypt/live/secure.zem.jp/privkey.pem;
        root                    /usr/share/nginx/html;
        access_log  /var/log/nginx/ssl-access.log  main;
}

最後に Nginx を再起動し、設定を反映します。

# systemctl reload nginx

あとはブラウザから「https://<ホスト名>/」を開きし、正常に HTTPS で通信できることを確認します。

lets-encrypt-setup2

HTTPS への強制リダイレクト

今の設定の状態では、安全な環境の確保に至るとは言えないでしょう。http:// へのアクセスを自動的に https:// に転送する設定をします。

ファイル /etc/nginx/nginx.conf を開き、「server_name」の明示と、「return 301」の命令を追加します。対象ホスト名に対するアクセスを、全て https:// にリダイレクトします。以下のように記述を追記するとき、リダイレクト先の URL は皆さんの環境にあわせて変更をお願いします。

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  secure.zem.jp;
        return  301 https://secure.zem.jp$request_uri;

Nginx を再起動したら、設定が有効になります。

# systemctl reload nginx

動作確認は curl で調べます。 http:// でリクエストしても、http:// に自動的にリダイレクトされるのが分かります。

# curl -v http://secure.zem.jp
* About to connect() to secure.zem.jp port 80 (#0)
*   Trying 133.242.68.208...
* Connected to secure.zem.jp (133.242.68.208) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: secure.zem.jp
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.6.3
< Date: Mon, 11 Jul 2016 10:02:38 GMT
< Content-Type: text/html
< Content-Length: 184
< Connection: keep-alive
< Location: https://secure.zem.jp/
<
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.6.3</center>
</body>
</html>
* Connection #0 to host secure.zem.jp left intact

証明書の自動更新設定

Let's Encrypt の証明書は有効期限が3ヶ月と短いため、定期的な更新作業が必要になります。この更新作業を手軽・確実に行うため「certbot-auto renew」コマンドが用意されています。

cron に以下の内容を登録します。「crontab -e」コマンドを実行し、次の行を追加します。

50 3 * * 0 certbot-auto renew --post-hook "systemctl restart nginx" 1 > /dev/null 2 > /dev/null

この設定を済ませておけば、自動的に更新されます。Let's Encrypt 証明書の有効期限が残り1ヶ月になれば、自動的に更新できるようになります。「--post-hook」オプションがあるのは、処理成功後に SSL の入れ替えをするため、Nginx の再起動を自動的に行います。

なお、これは毎週日曜日3時50分に実行しています。毎日1回実行する設定も可能ですが、たまたまサーバの障害などで実行されずに更新されないリスクを避ける狙いがあります。

certbot-auto には、便利なオプションが2つあります。

  • --dry-run … 実際に更新をしませんが、動作確認をシミュレーションできます。
  • --force-renew … 有効期限が1ヶ月未満にならなくても、強制的に有効期限を更新します。

有効期限の確認と自動更新

Let's Encrypt に限らず、SSL 証明書には有効期限が設定されています。この有効期限の確認はブラウザからだけでなく、サーバ内のコマンドライン上からも確認できます。ここでは、openssl コマンドを使い、証明書の有効期限を確認してみましょう。

# openssl x509 -in /etc/letsencrypt/live/secure.zem.jp/cert.pem -noout -dates
notBefore=Jul 11 08:40:00 2016 GMT
notAfter=Oct  9 08:40:00 2016 GMT

「notBefore」は証明書の生成日時です。また、「notAfter」は証明書の有効期限です。

ここで強制的に更新を行い、更新日が切り替わるか見てみましょう。「--force-renew」オプションを実行します。

# certbot-auto renew --force-renew --post-hook "systemctl restart nginx"

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/secure.zem.jp.conf
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/secure.zem.jp/fullchain.pem
-------------------------------------------------------------------------------

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/secure.zem.jp/fullchain.pem (success)

再び有効期限を確認します。先ほどより期限が延びているのが分かります。

# openssl x509 -in /etc/letsencrypt/live/secure.zem.jp/cert.pem -noout -dates
notBefore=Jul 11 08:54:00 2016 GMT
notAfter=Oct  9 08:54:00 2016 GMT

そして、証明書のパスも確認します。それぞれローテートされ、シンボリック・リンク先が「<ファイル名>1.pem」から「<ファイル名>2.pem」に変わっているのが分かります。

# ls -l /etc/letsencrypt/live/secure.zem.jp/
total 0
lrwxrwxrwx 1 root root 37 Jul 11 18:53 cert.pem -> ../../archive/secure.zem.jp/cert2.pem
lrwxrwxrwx 1 root root 38 Jul 11 18:53 chain.pem -> ../../archive/secure.zem.jp/chain2.pem
lrwxrwxrwx 1 root root 42 Jul 11 18:53 fullchain.pem -> ../../archive/secure.zem.jp/fullchain2.pem
lrwxrwxrwx 1 root root 40 Jul 11 18:53 privkey.pem -> ../../archive/secure.zem.jp/privkey2.pem

let's encrypt 設定のバックアップ

あとは、設定ファイルのバックアップが必要です。何らかの理由により紛失するのを避けるため、必ず設定ファイルのバックアップを取得し、安全な場所に保管をお願いします。

まとめ

インターネット上の通信を安全に保つには SSL/TLS 通信の設定が欠かせません。特にウェブサイト上では、オンライン・サービスの利用や、個人情報の利用など、暗号化や成りすましの防止により、セキュリティに気を配る必要がある場面が増えつつあります。

一般的に証明書の取得や設定には手間がかかりがちです。しかし、電子フロンティア財団(EFF)が提供する Let's Encrypt であれば、オンライン上で無料かつ簡単に証明書を作成できます。Let's Encrypt の目的とは、誰もが簡単に HTTPS を利用可能にすることです。そのための、仕組みやツールが提供されています。

この証明書の応用先は Nginx だけではありません。他にも Apache のウェブサーバや、Docker のレジストリにも応用が可能です。ぜひ、色々なシーンでご活用いただければと思います。

参考情報