Nginx クライアント証明書による認証の設定方法(OpenSSL)

ソフトウエア

Nginxを用いてクライアント証明書による認証を有効にする手順をまとめます。

  • クライアント証明書を利用した認証を有効にしたい
  • 無料で証明書を発行したい。

ベーシック認証よりも高度に制御をしたい場面がよく出てきます。

関連記事 Nginxにてベーシック(Basic)認証を有効にする手順

特定ユーザーのみアクセス許可を行いたい場合は、ベーシック認証を利用せずクライアント証明書による認証を実施します。手順をまとめましたのでご参考にしてください。

OpenSSLを利用したオレオレ認証局(CA)の準備

CA 認証局の鍵を作成

まずは設定ファイルの格納場所を任意でディレクトリを作成します。

# cd /etc/nginx
# mkdir certificates
# cd certificates

OpenSSLを利用したオレオレ認証局が利用する鍵(ca.key)を作成します。

# openssl genrsa -des3 -out ca.key 4096
# openssl genrsa -des3 -out ca.key 4096
Generating RSA private key, 4096 bit long modulus
........................++
.........................................................++
e is 65537 (0x10001)
Enter pass phrase for ca.key: [hogehoge] ← 任意のパスワード
Verifying - Enter pass phrase for ca.key: [hogehoge] ← 任意のパスワード

鍵を作成する際には、パスワードの入力を求められます。任意の文字列を入力してください。

秘密鍵の内容を確認するコマンド
# openssl rsa -in ca.key -text

鍵に利用するパスワードは非常に大切ですので忘れないように!

CA 証明書を作成

OpenSSLを利用してオレオレ認証局の証明書を作成します。CA認証局の有効期限は10年くらいの長期を設定します。

クライアント証明書の有効期限はブラウザ(Chrome,Edge,Firefox,Safari等)の仕様に影響を受けるので1年で設定します。

# openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
# openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
Enter pass phrase for ca.key:[hogehoge] ← CA証明局で指定したパスワード
Country Name (2 letter code) [XX]:JP ← 任意
State or Province Name (full name) []:Tokyo ← 任意
Locality Name (eg, city) [Default City]:Chuo-ku ← 任意
Organization Name (eg, company) [Default Company Ltd]:hogehoge LTD ← 任意
Organizational Unit Name (eg, section) []: ← 空白でOK
Common Name (eg, your name or your server's hostname) []:hoge.rin-ka.net ← 任意
Email Address []: ← 空白でOK

証明書作成で必要な項目を入力します。

  • Country Name : JP
  • State or Province Name : Tokyo
  • Locality Name : Chuo-ku
  • Organization Name : hogehoge LTD
  • Organizational Unit Name : 空白
  • Common Name : hoge.rin-ka.net
  • Email Address : 空白

「Organizational Unit Name」と「Email Address」は「空白」で構いませんが、他の項目は入力が必要です。

証明書の内容を確認するコマンド
# openssl x509 -in ca.crt -text

クライアント証明書の作成

クライアント証明書の秘密鍵を作成

OpenSSLを用いたクライアント証明書が利用する鍵(client01.key)を作成します。

# openssl genrsa -des3 -out client01.key 4096
# openssl genrsa -des3 -out client01.key 4096
Generating RSA private key, 4096 bit long modulus
........................++
.........................................................++
e is 65537 (0x10001)
Enter pass phrase for client01.key: [hogehoge] ← 任意のパスワード
Verifying - Enter pass phrase for client01.key: [hogehoge] ← 任意のパスワード

鍵を作成する際には、パスワードの入力を求められます。任意の文字列を入力してください。

秘密鍵の内容を確認するコマンド
# openssl rsa -in client01.key -text

鍵に利用するパスワードは非常に大切ですので忘れないように!

クライアント証明書のCSRを作成

CA認証局で署名するためクライアント証明書のCSRを作成します。

# openssl req -new -key client01.key -out client01.csr
# openssl req -new -key client01.key -out client01.csr
Country Name (2 letter code) [XX]:JP ← 任意
State or Province Name (full name) []:Tokyo ← 任意
Locality Name (eg, city) [Default City]:Chuo-ku ← 任意
Organization Name (eg, company) [Default Company Ltd]:hogehoge LTD ← 任意
Organizational Unit Name (eg, section) []: ← 空白でOK
Common Name (eg, your name or your server's hostname) []:clinet01.rin-ka.net  ← 任意
Email Address []: ← 空白でOK

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: ← 空白でOK
An optional company name []: ← 空白でOK

認証局で署名に必要な項目を入力します。

  • Country Name : JP
  • State or Province Name : Tokyo
  • Locality Name : Chuo-ku
  • Organization Name : hogehoge LTD
  • Organizational Unit Name : 空白
  • Common Name : client01.rin-ka.net
  • Email Address : 空白

「Organizational Unit Name」と「Email Address」は「空白」で構いませんが、他の項目は入力が必要です。

チャレンジ・パスワードの入力は任意です。

CSRの内容を確認するコマンド
# openssl req -in client01.csr -text

クライアント証明書にCA認証局で署名

CSRファイルを用いてクライアント証明書にCA認証局で署名を行います。

# openssl x509 -req -days 397 -in client01.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client01.crt
# openssl x509 -req -days 397 -in client01.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client01.crt
Signature ok
subject=/C=JP/ST=Tokyo/L=Chuo-ku/O=hogehoge LTD/CN=clinet01
Getting CA Private Key
Enter pass phrase for ca.key: [パスワード] ← CA認証局のパスワード

クライアント証明書の有効期限は、ブラウザ仕様に影響を受けない最大値(397日)をしていします。

サーバー証明書の有効期間が398日間(約13ヶ月)を超えた場合、ブラウザ側でエラーが表示されます。

ただ、クライアント証明書は、398日制限を受けないような気がしています。何故なら
Cybertrust で発行しているクライアント証明書は5年で設定されています。

証明書の内容を確認するコマンド
# openssl x509 -in ca.crt -text

PKCS #12 (pfx)の作成

WindowsやMacなどのクライアントPCにインポートしやすいように、クライアント証明書の保存形式を変更します。

# openssl pkcs12 -export -out client01.pfx -inkey client01.key -in client01.crt -certfile ca.crt
# openssl pkcs12 -export -out client01.pfx -inkey client01.key -in client01.crt -certfile ca.crt
Enter pass phrase for client01.key: ← 指定したパスワード
Enter Export Password:  ← 空白でOK
Verifying - Enter Export Password:  ← 空白でOK

「Verifying – Enter Export Password」空白で構いません。PCに証明書をインポートする際に利用するパスワードのことです。

変換して作成されたクライアント証明書を、何かしらの手段を使って取得してください。

クライアント証明書の失効

CA証明局の準備

クライアント証明書を失効させるためには、CA証明局で失効リストを管理する必要があります。サーバーの初期設定だと必要なファイルが提供されていないので準備をします。

# cd /etc/pki/CA/
# touch index.txt
# echo '00' > crlnumber

これで準備が整いました。

CA証明局のエラー

もし、設定ファイルが無い状態でクライアント証明書を失効させるとCA証明局のエラーが表示されます。

indexファイルが無い場合

/etc/pki/CA/index.txt: No such file or directory
unable to open '/etc/pki/CA/index.txt'

crlnumberファイルが無い場合

/etc/pki/CA/crlnumber: No such file or directory
error while loading CRL number
139925261584200:error:02001002:system library:fopen:No such file or directory:bss_file.c:398:fopen('/etc/pki/CA/crlnumber','r')
139925261584200:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:400:

エラーにヒントが記載されているので慌てずに設定を完了させてください。

クライアント証明書の失効コマンド

クライアント証明書を失効させるにはクライアント証明書とCA証明局の証明書が必要になります。コマンドを実行するとリスト(CRL)が更新されます。

 # openssl ca -gencrl -revoke [クライアント証明書] -out [失効リスト] -keyfile [CA証明局の秘密鍵] -cert [CA証明局の証明書]
 # openssl ca -gencrl -revoke client.crt -out crl.crt -keyfile ca.key -cert ca.crt
Enter pass phrase for ./ca.key: ← 指定したパスワード
Adding Entry with serial number 01 to DB for /C=JP/ST=Tokyo/L=Chuo-ku/O=hoge/CN=clinet
Revoking Certificate 01.
Data Base Updated

失効リストの更新が行われましたが、Nginxには更新情報が伝わらないので設定を反映させる必要があります。

証明書の失効リスト内容を確認するコマンド
# openssl crl -in crl.crt -text

1カ月後に何故かエラーが表示される

私は原因不明のエラーに悩まされ続けました。最初は正常に動作しているのに30日経つと認証エラーが表示されるようになる・・・

やっと原因がわかりました。

失効リスト(CRL)には有効期限があります。有効期限が切れるとサーバーは正常に動作しないので注意が必要です。有効期限の設定は /etc/pki/tls/openssl.cnf の default_crl_days です。規定値:30

失効リスト(CRL)の更新

失効リストの更新は定期的に実施する必要があります。初期値は30日なのでご注意ください

 # openssl ca -gencrl -out crl.crt -keyfile ca.key -cert ca.crt
Enter pass phrase for ./ca.key: ← 指定したパスワード

バッチ等で実行するようにしてください。更新後はNginxにもリロードして反映させてください。

証明書の失効リスト(CRL)更新スクリプト

 #!/bin/sh
openssl ca -batch -key [CA証明書パスワード] -gencrl -out /[hoge]/crl.crt -keyfile /[hoge]/ca.key -cert /[hoge]/ca.crt > /dev/null 2>&1
systemctl reload httpd > /dev/null 2>&1

作成したスクリプトをCronで実行させます。

Nginxの設定(Webサーバー)

ssl_verify_client  は http,server コンテキストに記載

クライアント証明書による認証制御するパラメータ(ssl_verify_client)は、http,server コンテキストに記載する設定です。

サイト全体に対してクライアント証明書による認証を行いたい場合は、気にしなくてもかまわないのです。サイトの一部のみ制御したい場合などは設定が複雑になってしまいます。

locationディレクティブに記入させてくれよ・・・

クライアント証明書による認証の有効化(サイト全体)

Nginxの設定は、クライアント証明を有効化するだけなので非常に簡単です。

server {
  listen 80 default_server;
  server_name  example.jp;

...省略...

  # クライアント証明の有効化
  ssl_verify_client on; ← サイト全体を有効化
  # CA証明局
  ssl_client_certificate "/etc/nginx/certificates/ca.crt";
  # クライアント証明書 失効
  ssl_crl  "/etc/nginx/certificates/crl.crt";

...省略...
}

サーバー ディレクティブに設定を追加します。

クライアント証明書による認証の有効化(サイト一部)

サイトの構成によって、一部のディレクトリだけ証明書認証を実施したい場合、逆に特定のパスを除外したい場合など使い分けを行いたい場合には次のように設定することで対応が可能です。

server {
  listen 80 default_server;
  server_name  example.jp;

...省略...

  # クライアント証明の有効化
  ssl_verify_client optional; ← optionalを指定し任意にする。結果が $ssl_client_verify に入る
  # CA証明局
  ssl_client_certificate "/etc/nginx/certificates/ca.crt";
  # クライアント証明書 失効
  ssl_crl  "/etc/nginx/certificates/crl.crt";

  # クライアント証明書の制御なし
    location / {
    # 特に気にせず設定を入れる
  ...省略...
    }

  # クライアント証明書の制御あり
    location / {
    # ssl_client_verify の値を条件にする
        if ($ssl_client_verify != SUCCESS) {
            # クライアント認証の結果がNGの場合は403でリダイレクト
            return 403;
        }
        ...省略...
    }
}

Nginxにクライアント証明書認証の反映

設定を変更したらNginxに反映させます。まずは設定ミスが無いかチェックします。

# nginx  -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

設定に不備が無ければ、設定をリロードします。

# systemctl reload nginx

クライアントPCの設定(Windows)

証明書のインストール

PKCS #12 (pfx)ファイルのクライアント証明書をインポートするのは非常に簡単です。ファイルをダブルクリックするとインストールが進みます。

登録が完了するとChromeとEdgeでクライアント証明書を利用することができます。

  • クライアント証明書のインストール
  • クライアント証明書のインストール
  • クライアント証明書のインストール
  • クライアント証明書のインストール
  • クライアント証明書のインストール
  • クライアント証明書のインストール
  • クライアント証明書のインストール

インストール作業はこれで完了です。

証明書のインストール(Chrome)

Chrome 画面右上の「縦三点リーダー」アイコンから「設定」を選択します。

「設定」ー「プライバシー」ー「証明書の管理」

証明書の管理画面(Chrome、Edge共通)が表示されるのでインポートするだけです。

証明書のインストール(Edge)

Edge 画面右上の「三点リーダー」アイコンから「設定」を選択します。

「設定」ー「プライバシー」ー「証明書の管理」

証明書の管理画面(Chrome、Edge共通)が表示されるのでインポートするだけです。

証明書のインストール(Firefox)

Firefoxの場合は、個別にクライアント証明書をインストールする必要があります。なんでOSの標準領域を使わないのか疑問ですが、こうなっているので仕方がない。

Firefox 画面右上の「ハンバーガー」アイコンから「設定」を選択します。

  • クライアント証明書のインストール
  • クライアント証明書のインストール

クライアント証明書のインストール確認

インポートされた証明書を確認してみます。「個人」タブにクライアント証明書が登録されます。

  • クライアント証明書のインストール

証明書認証の動作チェック

証明書認証が正しく動いた場合

クライアント証明書をインポートしたら、普段通りサイトにアクセスし動作チェックを行います。

ブラウザはキャッシュを利用するため想定外の動作が発生します。動作チェックを実施するときは、シークレット(プライベート)モードで実施することをお勧めします。

  • クライアント証明書の動作確認

クライアント証明書を利用した認証が動作している場合は、証明書の選択画面が表示されます。登録した証明書を選択し、正しければサイトが表示されます。

証明書が登録されていない場合

証明書認証が動作しているサイトに、証明書無しでアクセスするとエラーが表示されサイトを表示することができません。

  • クライアント証明書の動作確認

想定通り、アクセス権を制御することができました。

クライアント証明書が見つからない場合は、 サーバーから 400 Bad Request, No required SSL certificate was sent が返ってきます。

証明書が失効している場合

証明書認証が動作しているサイトに、失効した証明書でアクセスするとエラーが表示されサイトを表示することができません。

  • クライアント証明書の動作確認

想定通り、アクセス権を制御することができました。

クライアント証明書が失効している場合は、 サーバーから 400 Bad Request, The SSL certificate error が返ってきます。

あとがき

今回はOpenSSLとNginxを利用し、クライアント証明書による認証の設定を行いました。紹介した手順はベースとなる基本設定です。

本来はCA認証局、クライアント証明書に対して細かく設定を行う必要がありますが、動作させることを優先したので設定を割愛しました。

ベーシック認証よりも、安全性の高い証明書認証を構築することができました。

コメント