OpenSSL: проверка и разбор TLS-сертификатов в CLI
Уже забыли, когда последний раз сертификат на проде протухал неожиданно? Знакомо. OpenSSL умеет отвечать на вопросы о TLS-сертификатах быстрее, чем любой чекер из маркетплейса. Разбираем ключевые сценарии без воды.
Базовый разбор сертификата
Первая команда, с которой начинается любая диагностика — текстовый дамп сертификата.
Вывод показывает Subject, Issuer, сроки валидности, алгоритм подписи и публичный ключ. Для быстрой справки без простыни:
Флаг -in принимает путь к файлу. Если сертификат скачан через браузер — обычно в формате PEM или DER. OpenSSL понимает оба, но для DER нужен дополнительный флаг:
-noout убирает base64-блок из вывода. Полезно, когда нужен только структурированный результат, а не копия сертификата.
Срок действия: dates и проверка на просрочку
Для мониторинга удобнее получить только даты:
Типичный вывод:
Для автоматизации удобнее получить timestamp и считать разницу:
Если days_left отрицательный — сертификат уже просрочен.
Для проверки сразу нескольких хостов из inventory удобен однострочник:
-servername передаёт SNI — без него некоторые хосты отдают дефолтный сертификат.
Проверка цепочки: s_client и verify
Подключение с выводом сертификатов:
В выводе будет цепочка от leaf-сертификата до root CA. Для фильтрации только сертификатов:
Проверка цепочки через системный store:
Если проверка падает с error 20 at 0 depth lookup, значит, промежуточный CA не найден. Обычная причина — на сервере некорректно настроен chain.
openssl verify по умолчанию использует системный store. В Ubuntu это /etc/ssl/certs/ca-certificates.crt, в Alpine — отдельный пакет ca-certificates. Если проверка не работает — проверьте, что пакет установлен.
Короткая проверка без сохранения в файл:
Вывод Verify return code: 0 (ok) означает успех.
Чтобы не залипать в интерактивном режиме и завершать процесс с ошибкой при плохой цепочке:
Принудительная версия протокола или cipher — когда нужно убедиться, что сервер ещё принимает конкретный handshake:
Для внутреннего CA передайте бандл явно. Без -CAfile частный PKI обычно отвечает Verify return code: 21 (unable to get local issuer certificate):
Извлечение CN и SAN
Common Name извлекается напрямую:
Но CN давно недостаточно — современные сертификаты используют Subject Alternative Names (SAN). OpenSSL 1.1.1+ умеет вытащить их чисто:
Вывод:
Для получения только списка DNS-имен:
Если SAN отсутствует (старый сертификат), браузеры падают в fallback на CN. При проверке API-ендпоинтов это объясняет, почему curl ругается, а браузер открывает.
Сравнение сроков экспайри нескольких хостов
Скрипт для чека по списку хостов — практическая основа мониторинга:
Типичный вывод:
Отрицательные значения — просроченные сертификаты. В продакшене удобно завернуть в cron с уведомлением в чат при пороге меньше 30 дней.
Таблица ключевых флагов
| Команда | Флаг | Назначение |
|---|---|---|
x509 | -text | Полный дамп в текст |
x509 | -noout | Не выводить base64-блок |
x509 | -dates | NotBefore, NotAfter |
x509 | -subject | Subject (CN, O, OU) |
x509 | -issuer | Issuer (выдавщий CA) |
x509 | -fingerprint -sha256 | Отпечаток сертификата |
x509 | -enddate | Только срок окончания |
x509 | -ext san / subjectAltName | Альтернативные имена |
s_client | -connect host:port | Соединение с TLS |
s_client | -servername name | SNI (обязателен для vhost) |
s_client | -showcerts | Вывести всю цепочку |
s_client | -quiet | Не заходить в интерактивный режим |
s_client | -tls1_2 / -tls1_3 | Принудительная версия TLS |
s_client | -verify_return_error | Ненулевой код при ошибке валидации |
verify | -CAfile path | Файл доверенных CA |
verify | -partial_chain | Принять неполную цепочку |
openssl s_client умеет не только читать сертификаты. С флагом -starttls smtp или -starttls pop3 проверяет почтовые серверы. -http извлекает HTTP-заголовки через TLS-соединение. Это полезно для диагностики miTM-фильтров.
Все команды работают из коробки в любом дистрибутиве Linux. Никаких зависимостей, кроме самого OpenSSL — утилита есть на каждом сервере. Если нет — ставьтся за секунду: apt install openssl или apk add openssl.