SSL-сертификаты у клиента: 14 штук, три сервера, часть просрочена
После Heartbleed и POODLE взялись за инвентаризацию SSL у одного клиента - нашли 14 сертификатов с разными сроками, часть уже истекла. Строим реестр и мониторинг через Zabbix.
После серии SSL-инцидентов 2014 года (Heartbleed, POODLE) инвентаризация сертификатов у одного из клиентов выявила 14 SSL-сертификатов на разных серверах с хаотичными сроками - часть уже просрочены
После POODLE в октябре мы прошлись по конфигурациям TLS у всех managed-клиентов. Протоколы поправили, cipher suites подтянули - в общем, конфиги стали приличнее. Но в процессе у одного клиента всплыл отдельный вопрос, который раньше не стоял ребром: а сколько у них вообще SSL-сертификатов и когда они истекают?
Вопрос казался простым. Оказался нет.
Что нашли
Инфраструктура клиента - три физических сервера и несколько виртуальных машин. Внешне выглядело как «пара сайтов и почта». На деле оказалось, что сертификаты есть:
- На nginx-серверах - основной домен, поддомен для личного кабинета, поддомен API, тестовая копия (да, с отдельным сертом).
- На почтовом сервере - SMTP, IMAP, веб-интерфейс Roundcube - все три разные, потому что в разное время ставили разные люди.
- На внутренних сервисах - VPN-шлюз, внутренняя вики, мониторинг - здесь вперемешку самоподписанные и настоящие.
- Где-то ещё - резервный сервер, который давно не трогали, там nginx тоже запущен и тоже с сертификатом.
Итого насчитали 14 сертификатов. Это не потому что клиент делал что-то странное - просто инфраструктура росла по одному сервису, каждый ставил тот, кто его настраивал, и никто ни разу не собирал всё в одно место.
Дальше хуже: три сертификата уже истекли. Не «скоро истекут» - уже. Один - на тестовом поддомене, два - на внутренних сервисах. Браузеры ругались, но никто особо не смотрел, потому что «это же внутреннее».
Почему это проблема
Истёкший сертификат на внутреннем сервисе - это не просто раздражающий браузерный варнинг. Это:
- Потеря индикатора. Когда сертификаты всегда с варнингами, пользователи начинают кликать «продолжить» на автомате. Включая на тех ресурсах, где сертификат настоящий, но скомпрометированный.
- Зазор в мониторинге. Если никто не следит за сроками, сертификат на боевом сервисе тоже может протухнуть - просто заметят позже.
- Ручная работа в неудобный момент. Обычно об истечении узнают, когда пользователь пишет «у вас сайт сломался». Обновлять сертификат в таком режиме - не лучшая ситуация.
Как сделали реестр
Завели таблицу. Не какой-то специальный инструмент - просто структурированный документ, который живёт во внутренней вики и обновляется при каждом изменении. Колонки:
- домен / сервис
- сервер (hostname)
- порт
- кто выдал (CA или self-signed)
- дата истечения
- ответственный (кто продлевает)
- последнее обновление
14 строк занял час. Сразу стало видно, что три сертификата от одного CA истекают в течение двух недель, и их можно обновить одним заходом, а не тремя отдельными итерациями.
Мониторинг через Zabbix external check
Таблица - это хорошо, но полагаться на то, что кто-то будет её открывать и сверяться с датами вручную, наивно. Настроили проверку через Zabbix.
Zabbix поддерживает external checks - это когда вместо встроенного item type используется внешний скрипт, результат которого Zabbix читает как метрику. Скрипт простой: openssl s_client + openssl x509 -noout -enddate, считаем разницу с текущей датой в сутках.
#!/bin/bash
HOST=$1
PORT=${2:-443}
DAYS=$(echo | openssl s_client -connect "${HOST}:${PORT}" -servername "${HOST}" 2>/dev/null \
| openssl x509 -noout -enddate 2>/dev/null \
| sed 's/notAfter=//' \
| xargs -I{} date -d "{}" +%s \
| xargs -I{} bash -c 'echo $(( ($1 - $(date +%s)) / 86400 ))' _ {})
echo ${DAYS:-0}
Кладём в /etc/zabbix/externalscripts/ssl_cert_days.sh, в Zabbix создаём items типа External check с ключом ssl_cert_days.sh[{HOST.NAME},443]. Триггеры: warn при меньше 30 дней, critical при меньше 14.
Для внутренних сервисов, которые слушают на нестандартных портах - тот же скрипт, другой параметр.
Одно ограничение: скрипт не умеет проверять самоподписанные сертификаты с нестандартным CA - openssl s_client отказывается без явного указания -CAfile. Для самоподписанных пришлось добавить флаг -verify_return_error 0 и отдельный путь. Немного грязно, но работает.
Что в итоге
Три просроченных сертификата обновили. На два внутренних поставили самоподписанные с корректной датой (три года), на тестовый поддомен - заодно снесли, он был не нужен. Итого 13 живых сертификатов, все в реестре, все под мониторингом.
Обидно, что такого реестра не было с самого начала - это ведь не сложно. Просто никто не думал об этом как о чём-то, требующем учёта, пока не начали копать настройки после серии инцидентов этого года. Heartbleed в апреле заставил обновить OpenSSL, POODLE в октябре - выкинуть SSLv3, а инвентаризация в декабре показала, что у клиента просрочена часть сертификатов, о которых все забыли.
Теперь хотя бы будет алерт за месяц до того, как что-то протухнет.
- POODLE (CVE-2014-3566): SSLv3 отключаем везде, без исключений · 14 октября 2014
- TLS по OWASP: внутренний чеклист после трёх лет тяжёлых атак · 11 ноября 2014