エラーメッセージ
x509: certificate is not valid for any names, but wanted to match api.example.com
別の表記
- tls: failed to verify certificate: x509: certificate is not valid for any names, but wanted to match api.example.com
「wanted to match」の後の名前は、接続先として指定したものです。SAN 拡張がまったくない証明書の場合、Go は代わりに「x509: certificate relies on legacy Common Name field, use SANs instead」と報告します(CN が一致していたはずの場合)。
Go crypto/x509 — HostnameError for a certificate with no DNS SANs (e.g. IP-only or empty SAN list)
このエラーの意味
Go はホスト名を証明書と照合しようとしましたが、DNS 名がまったく見つかりませんでした。SAN 拡張は存在するものの、IP アドレス(またはほかの種類のエントリ)しか含まれておらず、コモンネームは考慮されません。Go は、証明書がどの名前にも対応していないことを報告し、続けて照合しようとした名前を示します。
発生する理由
IP アドレス用に作成された証明書をホスト名で使っている
よくあるノードや VM のアドレス向けに生成された証明書(IP SAN のみ)に、後から DNS 名でアクセスしているケースです。
別の用途向けの証明書
ときどきクライアント証明書、メール(S/MIME)用の証明書、コード署名証明書には DNS SAN が含まれていないため、サーバー証明書として使えません。
サーバーが誤った証明書を提示している
ときどき誤ってクライアント証明書や内部用の証明書が設定されたサーバーです。鍵のローテーションの後によく起こります。
修正方法
- 1.
SAN エントリと用途を確認する
SAN のリストからはどの種類の名前が含まれているかが、extendedKeyUsage からはそもそもサーバー証明書なのかどうかがわかります。
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -subject -ext subjectAltName,extendedKeyUsage - 2.
DNS SAN を含むサーバー証明書を発行する
クライアントが使う DNS 名を含め、クライアントがアドレスでも接続する場合は IP エントリも追加してください。
bash openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \ -addext "subjectAltName=DNS:api.example.com,IP:10.0.0.5" - 3.
または、証明書に記載されたアドレスで接続する
IP SAN が一致するのは、クライアントがその IP アドレスに接続した場合だけです。
go // If the certificate is meant for the IP address, dial the IP (it is matched against IP SANs) resp, err := client.Get("https://10.0.0.5:8443/")