エラーメッセージ
400 No required SSL certificate was sent
別の表記
- client sent no required SSL certificate while reading client request headers
ページのタイトルは「400 No required SSL certificate was sent」です。証明書の検証に失敗した場合、nginx は代わりに「400 The SSL certificate error」を表示します。ログの行は info レベルで書き込まれるため、error_log のデフォルトのレベルでは表示されません。
nginx — ssl_verify_client on, request without a client certificate
このエラーの意味
nginx は相互 TLS 用に設定されており(ssl_verify_client on)、リクエストは、クライアントが証明書を提示しなかった TLS 接続で届きました。nginx はハンドシェイクを失敗させるのではなく完了させ、すべてのリクエストにこの HTTP 400 ページで応答し、info レベルで「client sent no required SSL certificate」を記録します。修正が必要なのはクライアント側です。クライアントは、ssl_client_certificate に指定された CA が発行した証明書を提示しなければなりません。
発生する理由
クライアントが証明書を送信しなかった
よくある--cert/--key やライブラリの同等のオプションを指定していない curl、スクリプト、API クライアント、あるいは証明書のシークレットがないコンテナーや CI ジョブが該当します。
ブラウザーに一致する証明書がなかった
よくあるブラウザーが選択肢として提示するのは、nginx が通知する CA(ssl_client_certificate から取得)が発行した証明書だけです。別の CA の証明書しかない場合や、証明書が 1 つもインポートされていない場合、ブラウザーは何も送信しません。
nginx の手前でプロキシが TLS を終端している
ときどき前段にある CDN、ロードバランサー、別の nginx が、クライアント証明書なしで独自の TLS 接続を確立します。この場合、相互 TLS はその区間で設定する(またはエッジで行う)必要があります。
修正方法
- 1.
クライアント証明書を提示する
証明書と鍵をクライアントに渡してください。ブラウザーや Windows/macOS のキーストアには、PKCS#12 としてパッケージ化したファイルをインポートしてください。
bash curl --cert client.pem --key client.key https://mtls.example.com/ # Browsers: import the client certificate with its key as PKCS#12 openssl pkcs12 -export -in client.pem -inkey client.key -out client.p12 - 2.
mTLS サービスへのプロキシ:アップストリーム用の証明書を設定する
nginx 自身が mTLS サービスのクライアントになる場合は、proxy_ssl_certificate と proxy_ssl_certificate_key で、アップストリームへの接続に使う証明書を指定します。
text # nginx proxying to an mTLS upstream: present the client certificate on the upstream connection location / { proxy_pass https://mtls.example.com; proxy_ssl_certificate /etc/nginx/tls/client.pem; proxy_ssl_certificate_key /etc/nginx/tls/client.key; proxy_ssl_server_name on; } - 3.
必要な場所でだけ証明書を要求する
ssl_verify_client optional と、location ごとの $ssl_client_verify のチェックを組み合わせれば、ヘルスチェックや公開パスに証明書なしでアクセスできる状態を保てます。
text # Require the certificate only where needed ssl_verify_client optional; location /api/ { if ($ssl_client_verify != SUCCESS) { return 403; } }