nginxにてクライアント証明書による認証を行う場合は ssl_verify_clientの設定値にて処理することが可能。
いくつかのパターンによる実装を下記に列挙する。
クライアント証明書による認証を必須にする
on
で設定をすれば、SSLクライアント証明書による認証が行われる。
/path/to/ca.crt
で許可されている証明局となるとクライアント証明書が紐付いているかを確認している。
server {
....
ssl_verify_client on;
ssl_client_certificate /path/to/ca.crt;
....
}
認証局にて失効した証明書を拒否するには ssl_crl
を設定する
server {
....
ssl_crl /path/to/crl.pem;
....
}
証明書がある場合のみnginxにて認証を行う
optional
で設定をすれば、証明書がある場合のみSSLクライアント証明書による認証が行われる。
証明書がないリクエストは認証失敗とならない。証明書がないリクエストは $ssl_client_verify
変数はNONE
となる
server {
....
ssl_verify_client optional;
ssl_client_certificate /path/to/ca.crt;
....
}
SSLクライアント証明書を要求するが、認証はしない
optional_no_ca
とerror_page
でフォールバックすることで実現する。
optional_no_ca
は証明書が信頼されていない時は認証エラーが発生しないが、それ以外の証明書周りのエラーは発生する。
nginxのSSL認証はopensslに依存しているため、エラーの種類としてすべてを把握するのは難しいが、
少なくとも期限切れの証明書でリクエストした場合はnginxにて495エラーが発生した。
そのためerror_page
でフォールバックについても設定が必須となる。フォールバックする際は=
をつけるとプロキシ先のレスポンスコードが優先されるようになる。
(495エラー全てでフォールバックするので、optional
で設定しても問題なさそう)
server {
....
ssl_verify_client optional_no_ca;
ssl_client_certificate /path/to/ca.crt;
error_page 495 = @fallback;
location @fallback {
proxy_pass http://$your_domain;
}
....
}
アプリケーション側にてクライアント証明書を受取り、追加の認証処理を行う場合
mTLSでいうCertificate-Bound Access Tokens
などを実装したい場合が該当する。
nginxのL5レイヤーにて認証処理をしつつ、プロキシ先に認証結果や証明書情報を渡す必要がある。
on
で設定を行い、$ssl_client_verify
や $ssl_client_escaped_cert
などをヘッダ情報に付与した上で、アプリにproxyするようにする。
server {
....
ssl_verify_client on;
ssl_client_certificate /path/to/ca.crt;
location @fallback {
proxy_pass http://$your_domain;
proxy_set_header X-Client-Verify $ssl_client_verify;
proxy_set_header X-Client-Escaped-Cert $ssl_client_escaped_cert;
}
....
}
$ssl_client_cert
はdeprecatedになっているため、今後は使わない方が良さそう。
おわりに
仕事で設定することがあったので、忘れないようにメモをした。
Certificate-Bound Access Tokens
あたりとかの実装イメージも少し湧いた。アプリ側の処理はトークン発行時の証明書とfingerprintが一致しているか、とかになると思われる。