Сообщение об ошибке
invalid peer certificate: certificate not valid for name "api.example.com"; certificate is only valid for DnsName("www.example.com")
Ожидаемое имя и список предъявленных имён подставляются для каждой конкретной ошибки; IP-адреса выводятся как IpAddress(…). Более ранние релизы rustls выводили только имя варианта («invalid peer certificate: NotValidForName»).
rustls 0.23 (via reqwest, ureq, hyper-rustls) — CertificateError::NotValidForNameContext
Что это означает
Цепочка признана доверенной, но имени, к которому подключился клиент, нет среди альтернативных имён субъекта (SAN) сертификата. rustls 0.23 выводит и то и другое: ожидаемое имя и все имена, которые предъявляет сертификат (записи DnsName, IpAddress), так что несовпадение сразу видно.
Почему это происходит
Сертификат не покрывает это имя
частоВ списке SAN нет другого поддомена, домена без www или переименованного сервиса; wildcard-имя покрывает только одну метку.
Подключение по IP или внутреннему псевдониму
частоИмена сервисов (Kubernetes, docker-compose) или просто IP-адреса, для которых сертификат никогда не выпускался.
Сервер отправил сертификат по умолчанию
иногдаПрокси, у которого нет конфигурации для запрошенного имени, отдаёт сертификат другого сайта.
Как исправить
- 1.
Сравните предъявленные имена с URL
Они уже перечислены в сообщении; openssl подтвердит, что именно отправляет сервер.
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -ext subjectAltName - 2.
Переопределяйте адрес, а не имя
ClientBuilder::resolve в reqwest привязывает имя хоста к адресу сокета, поэтому при проверке по-прежнему используется имя, указанное в сертификате.
rust // Keep the certificate's name in the URL and send the connection to a specific address let addr: std::net::SocketAddr = "10.0.0.5:443".parse()?; let client = reqwest::Client::builder().resolve("www.example.com", addr).build()?; let resp = client.get("https://www.example.com/health").send().await?; - 3.
Перевыпустите сертификат со всеми используемыми именами
Добавьте в сертификат недостающие DNS-имена (или записи для IP-адресов).
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"