nginx連載6回目: nginxの設定、その4 - TLS/SSLの設定

株式会社ハートビーツのITインフラエンジニアがお届けするnginx連載の6回目。今回はnginxのTLS/SSLについての設定を確認していきます。以降、"TLS/SSL"のことを単に"SSL"と書きます。

TLS/SSLの設定

nginx.orgのパッケージからインストールしたnginxが提供している設定ファイルexample_ssl.confをサンプルとして説明します。なお、一部修正をしております。

server {
    listen       443;
    server_name  example.jp;

    ssl                  on;
    ssl_certificate      /etc/nginx/cert.pem;
    ssl_certificate_key  /etc/nginx/cert.key;

    ssl_protocols        SSLv3 TLSv1;
    ssl_ciphers          HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;

    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

SSLの基本設定

listenディレクティブとserver_nameディレクティブについては「nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定」で説明したので、詳しくはそちらを参照してください。

listenディレクティブ

listenディレクティブにはSSLで待ち受けるポート番号を明示的に指定します。次のように通常は443を指定します。

listen 443;

listenディレクティブにsslパラメータを付けると、そのポートでSSLを有効にして待ち受けるようになります。そのポートに関して後述するsslディレクティブをonにしたのと同じ動作になるため、sslディレクティブの記述は不要になります。

listen 443 ssl;

server_nameディレクティブ

server_nameディレクティブではSSLのサーバ証明書で指定したCN(Common Name)と同じサーバ名を指定します。

server_name example.jp;

SSLを有効化 - ssl

sslディレクティブをonに設定すると、SSLが有効になります。ただし、listenディレクティブでsslパラメータを指定したときには不要です。

ssl on;

サーバ証明書とプライベート鍵の指定 - ssl_certificateとssl_certificate_key

ssl_certificateディレクティブにサーバ証明書のファイルのパスを、ssl_certificate_keyディレクティブにプライベート鍵のファイルのパスを指定します。

ssl_certificate      /etc/nginx/cert.pem;
ssl_certificate_key  /etc/nginx/cert.key;

以上の設定をまとめると次のようになります。これらの設定を行えばSSLを利用できます。

server {
    listen       443;
    server_name  example.jp;

    ssl                  on;
    ssl_certificate      /etc/nginx/cert.pem;
    ssl_certificate_key  /etc/nginx/cert.key;
}

暗号に関する設定

使用するTLS/SSLのバージョンや暗号スイートについてはデフォルトの設定でも利用できますが、明示的に設定してみましょう。

使用するTLS/SSLのバージョン - ssl_protocols

ssl_protocolsには使用するSSLのバージョンを記述します。設定できるバージョンはSSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2です。

ただし、TLSv1.1とTLSv1.2はnginx 1.1.13以降および1.0.12以降でかつOpenSSL 1.0.1以降のときのみ動作します。

ssl_protocols SSLv3 TLSv1;

使用する暗号スイート - ssl_ciphers

ssl_ciphersにはSSLで使用する暗号スイートを指定します。デフォルト値はnginxのバージョンによって異なりますが、nginx 1.2.0では"HIGH:!ADH:!MD5"になります。指定できる暗号スイートはciphers(1) - OpenSSL

を参照してください。

「HIGH(公開鍵暗号の鍵長が128ビットより大きい)」、「aNULL(認証を提供しない暗号スイート)でない」、「MD5でない」ものを指定するにはと次のように記述します。

ssl_ciphers HIGH:!aNULL:!MD5;

参考までに、"openssl ciphers cipherlist '暗号スイートのリスト' -v"コマンドで利用できる暗号スイートの一覧を表示することができます。

$ openssl ciphers cipherlist 'HIGH:!aNULL:!MD5' -v
  略
AES256-SHA              SSLv3 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA1
CAMELLIA256-SHA         SSLv3 Kx=RSA      Au=RSA  Enc=Camellia(256) Mac=SHA1
PSK-AES256-CBC-SHA      SSLv3 Kx=PSK      Au=PSK  Enc=AES(256)  Mac=SHA1
AES128-SHA              SSLv3 Kx=RSA      Au=RSA  Enc=AES(128)  Mac=SHA1
CAMELLIA128-SHA         SSLv3 Kx=RSA      Au=RSA  Enc=Camellia(128) Mac=SHA1
PSK-AES128-CBC-SHA      SSLv3 Kx=PSK      Au=PSK  Enc=AES(128)  Mac=SHA1
  略

サーバが示した暗号スイートの優先 - ssl_prefer_server_ciphers

ssl_prefer_server_ciphersをonに指定すると、利用する暗号を選ぶ際に、SSLv3やTLSではサーバが示した暗号スイートが優先されます。offにするとクライアントのものが優先されます。デフォルトはoffです。onにするには次のように記述します。

ssl_prefer_server_ciphers on;

これはnginxの機能というよりはOpenSSLの機能で、SSL_CTX_set_options()にSSL_OP_CIPHER_SERVER_PREFERENCEを設定します。

SSLセッションキャッシュ

サーバの負荷を削減するために、SSLのセッションキャッシュを利用する設定を行います。

SSLセッションキャッシュの種類とサイズの指定 - ssl_session_cache

ssl_session_cacheにはSSLセッションキャッシュをどのように扱うかとそのキャッシュサイズを指定します。次のような文字列を指定することができます。

offセッションの再利用を明示的に禁止
noneクライアントにはセッションの再利用を明示的には禁止しないが、実際は利用不可
builtinOpenSSL組み込みを利用。一つのワーカープロセスのみが利用可能。
sharedすべてのワーカープロセスで共有。「shared:名前:サイズ」の形式で記述。

デフォルトはnoneです。

サーバの負荷を削減するためにはsharedを使うのが望ましいです。例えば、キャッシュサイズを10MBに設定するには次のように記述します。

ssl_session_cache shared:SSL:10m;

SSLセッションキャッシュのタイムアウトの指定 - ssl_session_timeout

ssl_session_timeoutディレクティブにはSSLセッションキャッシュに保管するSSLセッションの情報のタイムアウト時間を指定します。デフォルトは"5m"(5分)です。例えば、10分に設定するには次のように記述します。

ssl_session_timeout 10m;

設定TIPS

HTTPとHTTPSの設定を共有

上述しましたが、listenディレクティブにsslパラメータを付けると、そのポートでSSLを有効にして待ち受けるようになります。この機能を使い、次のようにsslパラメータを付けない80番ポートを指定したlistenディレクティブとsslパラメータを付けた443番ポートを指定したlistenディレクティブを設定すると、同じバーチャルサーバの設定でHTTPとHTTPSの両方を有効にすることができます。

server {
    listen          80;
    listen          443 ssl;
    server_name     example.jp;
    ssl_certificate /etc/nginx/cert.pem;
    ...
}

このときにはsslディレクティブを記述しないでください。TLS/SSLの有効・無効はlistenディレクティブのsslパラメータの有無で判断するようになります。もし、sslディレクティブでonを指定すると80番ポートでもTLS/SSLで待ち受けるようになってしまいます。

IPベースのバーチャルサーバ

TLS/SSL対応のIPベースのバーチャルサーバを複数持つためには、次のようにバーチャルサーバ毎に待ち受ける異なるIPアドレスをlistenディレクティブに指定します。

server {
    listen          192.0.2.1:443;
    server_name     example.jp;
    ssl             on;
    ssl_certificate /etc/nginx/cert-example.jp.pem;
    ...
}

server {
    listen          192.0.2.2:443;
    server_name     example.com;
    ssl             on;
    ssl_certificate /etc/nginx/cert-example.com.pem;
    ...
}

名前ベースのバーチャルサーバ

従来のTLS/SSLのプロトコルでは、ハンドシェイクの際にクライアントはURIのホスト名の情報をサーバに渡すことができないため、サーバはどのバーチャルサーバに対するリクエストが判断できませんでした。そのため、名前ベースのバーチャルサーバは利用できませんでした。しかし、Server Name Indication(以降、単にSNIと呼ぶ)というTLSの拡張機能により、ハンドシェイクの際にホスト名の情報を送ることができるようになりました。ただし、このSNIを利用するためには、サーバとクライアントの両方がSNIをサポートしている必要があります。なお、Server Name Indication - Wikipediaにサポート状況が掲載されています。クライアントにWindows XPの環境が残っている限り、実質的にSNIのサポートは難しいと思われます。

nginx自体はSNIに対応していますが、SNIの機能を有効にしてビルドされている必要があります。SNIの機能が有効であるかは次のようなコマンドを実行して、"TLS SNI support enabled"という文字列が出力されるかでわかります。

$ nginx -V 2>&1 | grep SNI
TLS SNI support enabled

SNIが有効であるときには、クライアントがリクエストしたホスト名に対応したバーチャルサーバの設定が適応され、そのサーバ証明書が使われます。

server {
    listen          443;
    server_name     example.jp;
    ssl             on;
    ssl_certificate /etc/nginx/cert-example.jp.pem;
    ...
}

server {
    listen          443;
    server_name     example.com;
    ssl             on;
    ssl_certificate /etc/nginx/cert-example.com.pem;
    ...
}

なお、SNIが無効であるとき、あるいはクライアントがSNIに対応していないときには、デフォルトサーバのバーチャルサーバが適応され、そのサーバ証明書が使われます。

以上でnginxのTLS/SSLの設定についての説明は終わりです。次回はよく使われる設定(認証、アクセス制御、rewriteモジュール等)について説明します。

株式会社ハートビーツのインフラエンジニアから、ちょっとした情報をお届けします。