Если API сообщает, что требуется клиентский сертификат, сначала отделите ошибку TLS от обычной HTTP-авторизации. Сравните запрос к одному адресу без сертификата и с заведомо действующей парой «сертификат + закрытый ключ»: если второй доходит до HTTP-ответа, граница mTLS найдена.
Не начинайте с замены токена или API-ключа. При обязательном mTLS сервер проверяет клиента во время TLS-рукопожатия, поэтому HTTP-заголовки могут вообще не дойти до приложения.
Что означает требование клиентского сертификата
В обычном HTTPS клиент проверяет сертификат сервера. При mutual TLS, или mTLS, проверка становится взаимной: сервер запрашивает сертификат клиента, проверяет цепочку доверия и требует доказать владение соответствующим закрытым ключом.
В TLS 1.3 сервер использует сообщение CertificateRequest, а клиент в ответ передаёт сертификат и подпись CertificateVerify. Если этот обмен не завершён, HTTP-запрос ещё не начался. Поэтому одна и та же проблема может выглядеть как TLS alert без кода HTTP, как ответ прокси либо как 401/403 после успешного рукопожатия — это зависит от точки, где настроена проверка.
Порядок диагностики mTLS
1. Зафиксируйте запрос без клиентского сертификата
Проверьте точный URL тем же методом и из той же сети, где возникает ошибка:
curl -v https://api.example.ru/health
Сохраните только безопасные признаки: этап соединения, TLS alert, HTTP-код и заголовки без токенов. Не добавляйте -k: этот параметр отключает проверку сертификата сервера и не исправляет отсутствие клиентского сертификата.
2. Повторите запрос с сертификатом и ключом
Для отдельных PEM-файлов команда выглядит так:
curl -v \
--cert client.crt \
--key client.key \
https://api.example.ru/health
Если сертификат хранится в PKCS#12, явно укажите формат:
curl -v \
--cert-type P12 \
--cert client.p12 \
https://api.example.ru/health
Не передавайте пароль к контейнеру в истории команд, логах или заявке в поддержку. Если серверный сертификат выпущен внутренним удостоверяющим центром, подключите его доверенный CA-файл через --cacert, а не отключайте проверку TLS.
Важно сравнивать одинаковые hostname, порт, путь, метод и сеть. Запрос по IP может попасть в другой виртуальный сервер из-за SNI и одновременно вызвать ошибку проверки имени в сертификате.
3. Посмотрите рукопожатие через OpenSSL
openssl s_client помогает увидеть, какой сервер отвечает, запрашивается ли сертификат клиента и на каком этапе обрывается соединение:
openssl s_client \
-connect api.example.ru:443 \
-servername api.example.ru \
-cert client.crt \
-key client.key
Параметр -servername важен, если на одном адресе размещено несколько TLS-конфигураций. Для неполной клиентской цепочки OpenSSL также позволяет передать отдельный файл промежуточных сертификатов через -cert_chain.
4. Проверьте сам сертификат
Сначала посмотрите владельца, издателя, срок действия и расширенное назначение ключа:
openssl x509 -in client.crt -noout \
-subject -issuer -dates -ext extendedKeyUsage
Затем убедитесь, что закрытый ключ действительно относится к этому сертификату:
openssl x509 -in client.crt -pubkey -noout | openssl sha256
openssl pkey -in client.key -pubout | openssl sha256
Хэши должны совпасть. Отдельно уточните требования сервера к издателю, цепочке, алгоритму подписи и назначению сертификата: действующий по дате сертификат всё равно может не соответствовать политике конкретного API.
5. Найдите точку завершения TLS
mTLS может завершаться не в приложении, а на nginx, балансировщике, API-шлюзе или CDN. Проверяйте конфигурацию и журналы именно этого узла.
В nginx результат проверки доступен в переменной $ssl_client_verify: она различает успешную проверку, ошибку и отсутствие сертификата. Также важны список доверенных CA и режим ssl_verify_client. Если TLS завершается на внешнем прокси, origin не получает исходный сертификат автоматически. Передавать сведения о клиенте дальше можно только по доверенному каналу; нельзя принимать такой заголовок напрямую из интернета.
Как читать результат проверки
| Наблюдение | Где искать причину | |---|---| | Без сертификата соединение отклонено, с сертификатом получен ожидаемый HTTP-ответ | mTLS работает; отказ без сертификата является ожидаемым | | Оба запроса обрываются до HTTP | SNI, доверенный CA, цепочка клиента, срок, ключ или политика TLS | | TLS завершается, затем приходит 401 или 403 | Правила доступа после TLS: привязка сертификата к учётной записи, токен, роль, путь | | В браузере работает, а в curl нет | Браузер мог выбрать сертификат из системного хранилища; curl нужно передать тот же сертификат и цепочку явно | | На origin работает, через публичный домен нет | Настройки mTLS, SNI или маршрута на внешнем балансировщике, CDN либо шлюзе |
Код HTTP сам по себе не доказывает, что клиентский сертификат принят. Сопоставляйте вывод клиента с журналом узла, который завершает TLS, и только затем переходите к логам приложения.
Частые причины отказа
Проверьте по порядку:
- Передан не тот сертификат или не тот закрытый ключ.
- Сертификат ещё не действует, истёк либо отклонён политикой сервера.
- Клиент не отправляет нужный промежуточный сертификат.
- Сервер доверяет другому удостоверяющему центру.
- Запрос уходит на другой виртуальный сервер из-за hostname, SNI или порта.
- mTLS настроен на балансировщике, а команда проверяет origin, или наоборот.
- TLS уже успешен, но приложение не сопоставило сертификат с нужным клиентом либо требует дополнительную авторизацию.
Меняйте по одному условию и повторяйте тот же запрос. Иначе легко принять случайное изменение маршрута или кэша за исправление сертификата.
Как мониторить API с mTLS
Закрытый mTLS endpoint нельзя проверять как обычную публичную страницу: отсутствие клиентского сертификата для него является нормальной причиной отказа. Нужен либо синтетический монитор, который безопасно хранит и предъявляет сертификат, либо отдельный ограниченный health endpoint в доверенном контуре. Такой endpoint не должен раскрывать данные и выполнять бизнес-операции.
Для внешнего публичного URL без клиентского сертификата можно настроить регулярную проверку доступности в Web-Puls. Это помогает заметить сетевой или серверный сбой, но не заменяет проверку закрытого mTLS-сценария с реальными правилами доступа.
После исправления проверьте четыре условия: правильный сертификат даёт ожидаемый ответ, запрос без него отклоняется на запланированной границе, в журналах видна причина решения, а ротация сертификата не требует аварийного изменения клиента.
Если неясно, где обрывается цепочка — на клиенте, балансировщике или API, — можно отправить заявку на профессиональную поддержку через /support/. Укажите публичный адрес, время и безопасный текст ошибки, но не прикладывайте закрытый ключ, пароль или сам клиентский сертификат.