API требует клиентский сертификат: как проверить mTLS

Разбираем mTLS по слоям: как отличить сбой TLS от HTTP-авторизации, проверить клиентский сертификат и найти точку отказа.

Если 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, и только затем переходите к логам приложения.

Частые причины отказа

Проверьте по порядку:

  1. Передан не тот сертификат или не тот закрытый ключ.
  2. Сертификат ещё не действует, истёк либо отклонён политикой сервера.
  3. Клиент не отправляет нужный промежуточный сертификат.
  4. Сервер доверяет другому удостоверяющему центру.
  5. Запрос уходит на другой виртуальный сервер из-за hostname, SNI или порта.
  6. mTLS настроен на балансировщике, а команда проверяет origin, или наоборот.
  7. TLS уже успешен, но приложение не сопоставило сертификат с нужным клиентом либо требует дополнительную авторизацию.

Меняйте по одному условию и повторяйте тот же запрос. Иначе легко принять случайное изменение маршрута или кэша за исправление сертификата.

Как мониторить API с mTLS

Закрытый mTLS endpoint нельзя проверять как обычную публичную страницу: отсутствие клиентского сертификата для него является нормальной причиной отказа. Нужен либо синтетический монитор, который безопасно хранит и предъявляет сертификат, либо отдельный ограниченный health endpoint в доверенном контуре. Такой endpoint не должен раскрывать данные и выполнять бизнес-операции.

Для внешнего публичного URL без клиентского сертификата можно настроить регулярную проверку доступности в Web-Puls. Это помогает заметить сетевой или серверный сбой, но не заменяет проверку закрытого mTLS-сценария с реальными правилами доступа.

После исправления проверьте четыре условия: правильный сертификат даёт ожидаемый ответ, запрос без него отклоняется на запланированной границе, в журналах видна причина решения, а ротация сертификата не требует аварийного изменения клиента.

Если неясно, где обрывается цепочка — на клиенте, балансировщике или API, — можно отправить заявку на профессиональную поддержку через /support/. Укажите публичный адрес, время и безопасный текст ошибки, но не прикладывайте закрытый ключ, пароль или сам клиентский сертификат.

Проверьте свой сайт прямо сейчас

Введите адрес сайта: Web-Puls покажет HTTP-код, время ответа и базовую диагностику. Для постоянного контроля можно подключить мониторинг.

Нужна помощь с диагностикой ошибки?

Опишите симптомы в короткой заявке: URL, код ответа, время появления и что менялось перед сбоем. Специалист поддержки оценит задачу и предложит формат работ.