エラーメッセージ
state=error: certificate verify failed (hostname mismatch)
別の表記
- OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 peeraddr=127.0.0.1:8443 state=error: certificate verify failed (hostname mismatch)
メッセージ全文:「SSL_connect returned=1 errno=0 peeraddr=<ip>:<port> state=error: certificate verify failed (hostname mismatch)」。ホスト名自体はメッセージに含まれません。URL と証明書を比較してください。
Ruby openssl (Net::HTTP verify_hostname, default true) — OpenSSL::SSL::SSLError from SSL_connect
このエラーの意味
チェーンは信頼されていますが、Net::HTTP の接続先のホスト名が、証明書のサブジェクト代替名に含まれていません。現在の Ruby のバージョンでは、ハンドシェイク中に OpenSSL がホスト名をチェックする(verify_hostname)ため、この問題は証明書の検証の失敗として表面化します。古い Ruby では、接続後に「hostname … does not match the server certificate」という別のエラーが発生していました。
発生する理由
証明書にこの名前が含まれていない
よくあるサブドメイン、apex ドメイン、名前が変わったホストが SAN のリストに含まれていないケースです。
IP アドレスや内部の別名で接続している
よくある接続先を IP アドレスやコンテナー名で設定したデータベース、Redis、API のクライアントです。
サーバーがデフォルトの証明書を返した
ときどき要求された名前を認識していないプロキシは、別のサイトの証明書を返します。
修正方法
- 1.
SAN のリストとホストを比較する
メッセージには名前が含まれていないため、証明書から名前を出力してください。
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -ext subjectAltName - 2.
証明書の名前を使い、アドレスを固定する
Net::HTTP#ipaddr= を使うと、SNI と検証にはホスト名を使ったまま、指定した IP に接続できます。
ruby # Connect to a specific address but verify the certificate's name (Net::HTTP#ipaddr=) http = Net::HTTP.new("www.example.com", 443) http.ipaddr = "10.0.0.5" http.use_ssl = true http.get("/health") - 3.
使用中のすべての名前を含めて再発行する
不足している名前を subjectAltName に追加してください。
bash openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \ -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com"