Сообщение об ошибке
SSL_do_handshake() failed (SSL: error:0A000418:SSL routines::tlsv1 alert unknown ca:SSL alert number 48)
Также выводится как
- SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
- error:0A000418:SSL routines::tlsv1 alert unknown ca
nginx записывает эту ошибку в журнал с уровнем info как «SSL_do_handshake() failed (SSL: error:0A000418:SSL routines::tlsv1 alert unknown ca:SSL alert number 48) while SSL handshaking, client: …». CLI-утилита openssl выводит «…:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:…». Клиенты на OpenSSL отправляют это оповещение одинаково для недоверенных, самоподписанных и неполных цепочек.
nginx error log / OpenSSL — TLS alert 48 (unknown_ca) received from the peer
Что это означает
Другая сторона соединения прервала рукопожатие оповещением TLS 48 (unknown_ca): она не смогла построить цепочку от полученного сертификата до CA, которому доверяет. В журнале сервера (как здесь, в nginx) это значит, что клиент отверг сертификат сервера. На клиенте это значит, что сервер отверг клиентский сертификат при взаимной TLS-аутентификации. Проблема никогда не у той стороны, которая записала оповещение в журнал: причина в сертификате, отправленном другой стороне.
Почему это происходит
Журнал сервера: клиенты не доверяют сертификату сервера
частоСамоподписанные сертификаты или сертификаты частного CA, отсутствующий промежуточный сертификат или сертификат для внутреннего использования, который отдаётся внешним клиентам. Каждый клиент, у которого не проходит подключение (curl, API-клиенты, мониторинг), оставляет одну такую строку.
На стороне клиента: сервер не доверяет вашему клиентскому сертификату
частоПри взаимной TLS-аутентификации клиентский сертификат выпущен CA, который не указан в настройках сервера как доверенный, или клиент не отправляет свой промежуточный сертификат.
Сканеры и пробные подключения
иногдаСканеры, которые обходят весь интернет, подключаются, ничему не доверяя, и прерывают соединение с этим оповещением; единичные строки с неизвестных адресов безвредны.
Как исправить
- 1.
Выясните, какой сертификат был отвергнут
Если ошибка записана в журнале сервера, проверьте цепочку сервера снаружи; если на клиенте со взаимной TLS-аутентификацией — сверьте клиентский сертификат с CA, который нужен серверу.
bash # In a SERVER log: a client rejected the server's certificate (e.g. missing intermediate) openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:|Verify return code' # On a CLIENT: the server rejected your client certificate (mutual TLS) - 2.
Сервер: отдавайте полную цепочку от публично доверенного CA
Для публичных эндпоинтов используйте сертификат от публичного CA и настройте полную цепочку. Для внутренних эндпоинтов убедитесь, что у каждого клиента есть внутренний корневой сертификат.
text # nginx: the chain clients need, leaf first ssl_certificate /etc/nginx/tls/fullchain.pem; ssl_certificate_key /etc/nginx/tls/privkey.pem; - 3.
Взаимная TLS-аутентификация: выпускайте клиентские сертификаты от доверенного CA
Проверьте клиентский сертификат по CA, указанному в настройках сервера (ssl_client_certificate в nginx), и отправляйте промежуточный сертификат клиента вместе с его сертификатом.
bash # Mutual TLS: is the client certificate issued by the CA the server trusts? openssl verify -CAfile server-trusted-client-ca.pem -untrusted client-intermediate.pem client.pem # Send the client's intermediate too, if it has one cat client.pem client-intermediate.pem > client-chain.pem curl --cert client-chain.pem --key client.key https://mtls.example.com/
Связанные ошибки
SSL routines:ssl3_read_bytes:ssl/tls alert bad certificateOpenSSLSSL routines:ssl3_read_bytes:tlsv13 alert certificate requiredOpenSSL (client side)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)remote error: tls: unknown certificate authorityGo crypto/tls