Сообщение об ошибке
x509: certificate is valid for example.com, not api.example.com
Оба значения подставляются при каждой ошибке свои: сначала имена, которые покрывает сертификат, затем имя, которое запросил ваш клиент.
Go crypto/x509 — HostnameError from VerifyHostname / TLS dials
Что это означает
Установка TLS-соединения дошла до чтения сертификата, но ни одно из его альтернативных имён субъекта (SAN) не совпадает с именем хоста, к которому подключался клиент. Ошибка показывает обе стороны, поэтому расхождение видно сразу: сертификат покрывает X, а вы запрашивали Y. Обратите внимание: современная проверка использует только SAN, а устаревшее поле общего имени (CN) игнорируется.
Почему это происходит
В списке SAN нет используемого имени
частоСертификат, выпущенный для example.com, не покрывает api.example.com (а wildcard *.example.com покрывает только один уровень: не сам example.com и не a.b.example.com). Для новых поддоменов сертификаты нужно перевыпускать.
Подключение по внутреннему псевдониму
частоПри подключении по имени сервиса docker-compose или другому внутреннему псевдониму сервер предъявляет сертификат на то имя, которым он себя считает: в SAN указаны публичные DNS-имена, а не ваш псевдоним, поэтому сопоставление не проходит. При подключении просто по IP-адресу вместо этой ошибки появляется родственная: «x509: cannot validate certificate for 10.0.0.5 because it doesn't contain any IP SANs».
Сервер отдаёт не тот сертификат или сертификат по умолчанию (SNI)
иногдаМультитенантные ingress-контроллеры выбирают сертификат по SNI. Если клиент не задаёт ServerName или в ingress нет правила для этого хоста, клиент получает сертификат по умолчанию — часто заглушку вроде «Kubernetes Ingress Controller Fake Certificate».
Как исправить
- 1.
Перевыпустите сертификат со всеми именами, которые вы действительно используете
Укажите все имена хостов как SAN при выпуске сертификата; чтобы узнать, что покрыто сейчас, посмотрите текущий список SAN.
bash echo | openssl s_client -connect host:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -ext subjectAltName # request with SANs: openssl req -new -key key.pem -out req.csr \ -subj "/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:api.example.com" - 2.
Подключайтесь по имени или явно задайте ServerName
Если сетевой адрес должен отличаться от имени в сертификате (VIP, проброс портов, sidecar), сохраните проверку полноценной: явно укажите в настройках TLS, какой идентификатор сервера вы ожидаете.
go conn, err := tls.Dial("tcp", "10.0.0.5:443", &tls.Config{ ServerName: "api.example.com", // matched against SANs, sent as SNI })