クライアント証明書認証とは、サービスを利用するユーザーに証明書を発行し(これを「クライアント証明書」と呼びます)その証明書によってユーザーを認証する仕組みのことです。一般的なユーザーIDとパスワードの認証に加えて、このクライアント証明書認証を導入することによって、ログイン時のセキュリティを強化することができます。そこで今回は、プライベート認証局の構築とクライアント証明書認証の発行、Apache httpd 2.4 でのクライアント証明書認証の設定手順をまとめてみました。
プライベート認証局の構築
まずはじめに、クライアント証明書を発行するためのプライベート認証局を構築します。
「プライベート認証局の構築」と書くとなにやら大変そうですが、CentOS には初期状態で認証局構築ツールが入っていますので、簡単にプライベート認証局を構築できます。
・OpenSSL の設定をプライベート認証局構築用に変更します。
sudo vim /etc/pki/tls/openssl.cnf
(略)
basicConstraints=CA:FALSE
↓
basicConstraints=CA:TRUE
[ v3_ca ]
(略)
# nsCertType = sslCA, emailCA
↓
nsCertType = sslCA, emailCA
・プライベート認証局構築スクリプトを編集し、有効期限を30年に変更します。
sudo vim /etc/pki/tls/misc/CA
↓
CADAYS="-days 10950" # 30 years
(補足)CentOS8には /etc/pki/tls/misc/CA がありませんので、インストールしてください。
関連記事:CentOS8 に /etc/pki/tls/misc/CA をインストールする方法
「/etc/pki/CA/」ディレクトリ下に(もしこのディレクトリが無かったら作成してください)証明書のラベル付けに使用するシリアルファイルを作成します。
sudo vim /etc/pki/CA/serial
・プライベート認証局を作成します。青文字の箇所以外は<空エンター>でOKです。
sudo /etc/pki/tls/misc/CA -newca
<空エンター>
(略)
Enter PEM pass phrase: 1234 ←表示されません
Verifying - Enter PEM pass phrase: 1234 ←表示されません
(略)
Country Name (2 letter code) [XX]: JP
State or Province Name (full name) []: Tokyo
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []: private-ca
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/./cakey.pem: 1234 ←表示されません
Check that the request matches the signature
Signature ok
(略:入力した認証局の情報が表示されます)
Certificate is to be certified until Apr 15 20:52:22 2120 GMT (36500 days)
Write out database with 1 new entries
Data Base Updated
プライベート認証局の秘密鍵のパスフレーズを削除します。
Enter pass phrase for cakey.pem: 1234 ←表示されません
プライベート認証局の秘密鍵のパーミションを変更
以上で、プライベート認証局の構築完了です。「/etc/pki/CA/cacert.pem」がプライベート認証局の証明書になります。(これを後ほど Apache httpd に設定します)
クライアント証明書の発行の下準備
プライベート認証局構築用になっている OpenSSL の設定を、クライアント証明書発行用に変更します。
sudo vim /etc/pki/tls/openssl.cnf
(略)
default_days = 365
↓
default_days = 36500
[ usr_cert ]
(略)
basicConstraints=CA:TRUE
↓
basicConstraints=CA:FALSE
# nsCertType = client, email, objsign
↓
nsCertType = client, email, objsign
[ v3_ca ]
(略)
nsCertType = sslCA, emailCA
↓
# nsCertType = sslCA, emailCA
クライアント証明書の発行
本題のクライアント証明書の発行です。
適当な場所に作業用ディレクトリを作成して、そのディレクトリに移動してください。
cd /etc/pki/tls/client/
クライアント証明書用の秘密鍵を作成します。
・クライアント証明書の発行要求(CSR)を作成します。青文字の箇所以外は<空エンター>でOKです。
sudo openssl req -new -key client.key -out client.csr
State or Province Name (full name) []: Tokyo
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []: client
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
・クライアント証明書を発行します。
sudo openssl ca -in client.csr -out client.crt
(クライアント証明書の発行要求の内容が表示されます)
Certificate is to be certified until Apr 15 21:26:01 2120 GMT (36500 days)
Sign the certificate? [y/n]: y
1 out of 1 certificate requests certified, commit? [y/n] y
Write out database with 1 new entries
Data Base Updated
・秘密鍵と発行したクライアント証明書を PKCS#12 ファイルにまとめます。(設定したパスワードはブラウザにインストールする時に必要になります)
sudo openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12
Verifying - Enter Export <パスワード>
この PKCS#12ファイルを使ってクライアント証明書をWebブラウザにインストールしますので、クライアントとなるパソコンにコピーしておきましょう。(Webブラウザへのインストール方法は「<Webブラウザ名> クライアント証明書」で検索してください)
Apache httpd 2.4 でのクライアント証明書認証の設定
青字の部分が、Apache httpd 2.4 でのクライアント証明書認証の設定です。クライアント証明書認証は、TLS/SSL のオプションという位置づけのためサーバー側の TLS/SSL 設定は必須です。
<VirtualHost *:443> ServerName www.example.com DocumentRoot "/var/www/html" SSLEngine on Header always set Strict-Transport-Security "max-age=31536000" SSLCertificateFile /etc/pki/tls/certs/server.crt SSLCertificateKeyFile /etc/pki/tls/private/server.key SSLCACertificateFile /etc/pki/CA/cacert.pem SSLVerifyDepth 1 <Directory "/var/www/html"> Options FollowSymLinks AllowOverride None # Require all granted SSLVerifyClient require Require expr %{SSL_CLIENT_S_DN_CN} == 'client' </Directory> SetEnvIf Request_URI "\.(gif|jpg|png|css|js)$" nolog ErrorLog logs/error_log CustomLog logs/access_log combined env=!nolog </VirtualHost>
設定の補足
SSLCACertificateFile /etc/pki/CA/cacert.pem
クライアント証明書を発行した認証局(冒頭で作成したプライベート認証局のことです)の証明書「/etc/pki/CA/cacert.pem」を指定します。(このディレクティブは Directory ディレクティブの下や .htaccess には書けません)
SSLVerifyDepth 1
中間証明書を発行した認証局の最大数です。今回の場合は、SSLCACertificateFile で指定した認証局が直接クライアント証明書を発行していますので「1」を指定します。
SSLVerifyClient require
クライアント証明書認証の検証レベルを指定します。クライアント証明書認証を必須とする場合は「require」を指定します。
Require expr %{SSL_CLIENT_S_DN_CN} == 'client'
このディレクティブは必須ではありませんが、上記のように指定するとコモンネーム(SSL_CLIENT_S_DN_CN)が「client」のクライアント証明証のみ認証します。組織名(SSL_CLIENT_S_DN_O)や部門名(SSL_CLIENT_S_DN_OU)なども指定することができます。
参考資料:mod_ssl Environment Variables
以前よくつかわれていた SSLRequire は、非推奨になったため Require expr の利用が推奨されています。
Cannot perform Post-Handshake Authentication エラー対処法
TLS1.3 を有効にしている場合、以下のようなエラーが発生して、クライアント証明書認証ができない場合があります。
[Thu May 14 05:32:08.231184 2020] [ssl:error] [pid 1858:tid 140234977113856] [client 192.168.56.1:50202] AH10158: cannot perform post-handshake authentication
[Thu May 14 05:32:08.231224 2020] [ssl:error] [pid 1858:tid 140234977113856] SSL Library Error: error:14268117:SSL routines:SSL_verify_client_post_handshake:extension not received
その場合は、TLS1.3 を無効にし、TLS1.2 のみ有効にしてください。
sudo vim /etc/httpd/conf.d/ssl.conf
↓
SSLProtocol -all +TLSv1.2
おわりに
テレワークが一気に普及したことにより、特定の端末からのみからサービスにアクセスさせたいという要望が増えています。そんな時にはこのクライアント証明書認証が活用できそうですね。
コメント