showcert - маленькая CLI утилитка, альтернатива openssl для просмотра сертификатов. Она умеет 1% того, что может openssl, но зато умеет [почти] все, что нужно в обычной админской жизни и даже немного больше чем openssl. И гораздо проще в использовании. Основные функции:

  • Взять сертификат (или цепочку) из stdin, файла(файлов) или из TLS сервиса (HTTPS, POP3S, IMAPS), в том числе через STARTTLS (для SMTP, POP3, IMAP)

  • Проверить валидность сертификата.

  • Проверить "свежесть" сертификата, и если срок действия истекает через N дней - передать это в коде завершения.

  • Распечатать сертификат (цепочку) в краткой форме (только основное), полной, в PEM формате (для сохранения в cert.pem или fullchain.pem).

И все это делается простым, интуитивно-понятным образом, для людей.

Когда я хочу проверить дату истечения, например, почтового сертификата яндекса, немного гуглю, потом сноровисто пишу что-то вроде:

$ echo | openssl s_client -connect mx.yandex.ru:25 -starttls smtp 2>&1 | openssl x509 -noout -dates

Когда я печатаю эту строчку, вспоминаю немало многокоренных слов из флотской службы, а ведь я даже не служил... А теперь, представьте, что мы хотим не просто увидеть дату, а еще и как-то что-то сделать, если до истечения останется меньше 20 дней... как будет выглядеть команда? Мне вообще сложно представить, как это можно автоматизировать через openssl и простые шелл скрипты.

Просмотр сертификатов через showcert

А теперь (после установки: pip3 install showcert) сравните с:

$ showcert mx.yandex.ru:25
Names: mx.yandex.ru mx.yandex.net
notBefore: 2022-07-25 11:16:45 (15 days old)
notAfter: 2023-01-22 20:59:59 (165 days left)
Issuer: C=BE O=GlobalSign nv-sa CN=GlobalSign RSA OV SSL CA 2018

Ну разве не проще? showcert сам (по номеру порта) догадывается, как начать STARTTLS (но конечно же, это можно переопределить через опцию -t / --starttls, например, -t no или -t imap).

Предупредить о том, что сертификат скоро протухнет? Окей!

$ showcert mx.yandex.ru:25 -qw 200 || echo PROBLEM
mx.yandex.ru:25 expires in 165 days
PROBLEM

-q - тихий режим, не печатать лишнего, только предупреждения, -w 200 - завершаться с кодом ошибки, если до протухания меньше 200 дней.

Проверить https вебсайт? showcert github.com (Несложный синтаксис?)

"Скопировать" fullchain.pem с сервера (взять его и распечатать в PEM):

$ showcert google.com --chain -o pem > fullchain.pem

У меня после этого дампа (не с гугла, а со своего другого сервера) - даже md5 файлов сошелся!

Так же можно посмотреть или проверить один или несколько локальных файлов сертификатов (fullchain.pem или cert.pem).

$ showcert fullchain.pem

Можно добавить --chain чтобы увидеть всю цепочку. И ключ -w тоже работает.

Формат вывода сертификатов

По умолчанию (-o brief) выводится краткая информация (все, что обычно важно, минимум лишнего). -o full дает полный дамп (как openssl), -o pem даст сертификат в PEM формате (удобно сделать редирект в файл и получить его на диске).

Еще есть удобный формат -o names - просто распечатывает все имена из сертификата, и его вариация -o dnames, о ней ниже.

Сахар для LetsEncrypt

Мы много используем LetsEncrypt, поэтому showcert удобен для этого. На сервере могут быть десятки (а то и сотни) сайтов, у каждого сертификат. Да, certbot renew в теории должен обновлять их, но сайты живые, постоянно разрабатываются, причем разными людьми и с ними иногда происходят разные чудеса. То поменяется DocumentRoot, то появятся правила rewrite/redirect, которые блокируют проверку, то доменное имя куда-то уедет... В общем, обновления иногда фейлятся и сертификаты протухают. А когда сайтов много, что-то проблемное случается регулярно.

Мы используем okerr (статья про okerr на хабре) для мониторинга. Наш собственный open source гибридный мониторинг. Раньше мы использовали скрипт, создавал индикатор типа sslcert для каждого сайта (это тоже не очень удобно, так как сайты ведь иногда и умирают или переезжают на другой сервер). Но с showcert стало еще проще:

Простой приятный способ проверить, что все LetsEncrypt сертификаты еще свежи:

# showcert :le -qw
/etc/letsencrypt/live/example.com/fullchain.pem expires in 19 days
/etc/letsencrypt/live/example.net/fullchain.pem expires in 19 days
# echo $?
2

Команда выше - синоним showcert /etc/letsencrypt/live/*/fullchain.pem -qw, а код :le запомнить проще, чем путь к сертификатам. Ну и код завершения удобен, чтобы использовать его в мониторинге, собственных скриптах. У нас showcert вызывается из okerrupdate/okerrmod, в окерр внешние скрипты проверки цепляются одной строчкой, но если у вас другой мониторинг - тоже сможете легко подцепить showcert.

Если не используете никакой мониторинг, то showcert :le -qw в cron раз в сутки - оповестит заранее о сертификатах, которые своевременно не смогли обновиться, и у вас будет время починить.

Еще одна опция: -o dnames печатает имена через -d, это удобно чтобы скармливать их certbot:

$ showcert -o dnames habr.ru
-d habr.ru -d www.habr.ru

Для двух имен, как у хабра - это не имеет особого смысла, но если у сертификата имен много, и вам нужно пересоздать его - вручную печатать их можно и ошибиться. Проще через showcert получить часть команды и просто использовать ее (или даже использовать сам showcert в команде:

certbot certonly --webroot /var/www/habr `showcert -o dnames habr.ru`

Попробуйте, например, showcert -o dnames google.com.

Заключение

Утилита простая, синтаксис очевидный и простой, не требует запоминания и для большинства частых админских операций - работает замечательно! Пригодна для отслеживания протухающих сертификатов (через openssl это сложнее). Без нее можно обойтись, но с ней проще.

Очень советую попробовать :-)

Комментарии (29)


  1. acmnu
    16.08.2022 11:30

    $ echo | openssl s_client -connect mx.yandex.ru:25 -starttls smtp 2>&1 | openssl x509 -noout -dates

    function showcert(){
        echo | openssl s_client -connect ${1} -starttls smtp 2>&1 | openssl x509 -noout -dates
    }

    Просто добавить в bashrc. Если уж написали эту строчку, то сделать ее переиспользуемой не сложно.

    Атеперь, представьте, что мы хотим не просто увидеть дату, а еще и как-то что-то сделать, если до истечения останется меньше 20 дней... как будет выглядеть команда?

    Зачем это делать через какие-либо скрипты? Если вы используете LE, то у вас должна в кроне стоять задача на замену сертификата, как это рекомендуется создателями этой системы. И там все за вас уже сделано.

    Ну и должен быть мониторинг, а любой мониторинг умеет в проверку сертификатов.

    Т.е. showcert без сомнения хорошая, удобная вещица для ad-hoc проверок. Но при чем здесь shell, флот и триггер скриптов мне не понятно.


    1. xenon Автор
      16.08.2022 12:05
      +4

      Еще сделать showcert_imap, showcert_pop3, showcert_https. Сделать удобный общий showcert, который будет вызывать нужный из них (будет догадываться, что для smtp нужна --starttls, а для https или pop3s - не нужна). Добавить туда выгрепывание "Verify return code" (т.к. он выдается на stdout). И showcert_file конечно. Добавить опцию показа всей цепочки. Еще может пару мелочей (та же проверка на "осталось больше N дней") - но ничего невозможного. И получим в итоге замечательный showcert с тем же функционалом, написанный на шелле и живущий в .bashrc.

      А когда надоест его устанавливать на новые сервера через vim .bashrc, можно переписать его на чем-нибудь и оформить в виде deb или rpm пакета, или питоновского wheel, и тогда получим полный аналог! :-)


    1. inkvizitor68sl
      16.08.2022 14:58

      letsencrypt не отменяет мониторинга сертификатов.

      Сейчас вот, например, что-то поменялось в API и перестали продляться/выписываться сертификаты через dns+cloudflare на debian 11 пакетом из main


      1. xenon Автор
        16.08.2022 15:42
        +2

        Как по мне: вообще ничто не отменяет мониторинга чего-угодно. Из нескольких сотен "ненужных" индикаторов. которые я добавил "ну пусть будут", для внушительности, с уверенностью, что они никогда не сработают - несколько таки сработали.

        Ожидаемое может и никогда не случиться, непредсказуемое случится обязательно.


        1. inkvizitor68sl
          16.08.2022 15:43

          Да это понятное дело, я про конкретный случай -)

          У меня LE примерно 20% доменов не может продлить.


  1. acmnu
    16.08.2022 11:33

    Да, certbot renew в теории должен обновлять их, но сайты живые, постоянно разрабатываются, причем разными людьми и с ними иногда происходят разные чудеса. То поменяется DocumentRoot, то появятся правила rewrite/redirect, которые блокируют проверку, то доменное имя куда-то уедет... В общем, обновления иногда фейлятся и сертификаты протухают. А когда сайтов много, что-то проблемное случается регулярно.

    Ааа. Вот в чем проблема. Ну pip install в вашей жизни ничего не решит толком. Надо исправлять саму возможность возникновения подобных проблем, а не отказываться от certbot renew.


    1. xenon Автор
      16.08.2022 11:41
      +1

      От него никто не отказывается (Что же, по вашему, мы руками что ли обновляем каждый сертифика?). Certbot в кроне каждое утро обновляет что может. А мониторинг - следит, чтобы все было обновлено. Ну и добавлять в мониторинг каждый раз новый сайт неудобно, а так у нас вместо тысячи проверок на тысячу сайтов всего одна проверка с сутью "все LE сертификаты свежи".


      1. acmnu
        16.08.2022 15:08

        Ну и добавлять в мониторинг каждый раз новый сайт неудобно, а так у нас вместо тысячи проверок на тысячу сайтов всего одна проверка с сутью "все LE сертификаты свежи".

        Любая система мониторинга умеет в шаблоны.


  1. ifap
    16.08.2022 12:58
    -1

    А не проще зайти с другого конца: инфа о всех полученных сертификатах заносится в единую базу и по ней уже отслеживаются даты протухания, без перезапросов к серверам?


    1. baldr
      16.08.2022 13:03
      +3

      А вы сами-то так делаете?


      1. ifap
        16.08.2022 13:09

        У меня самого нет столько серверов под началом, чтобы специальную инфраструктуру под их мониторинг мутить, потому и интересуюсь.


    1. xenon Автор
      16.08.2022 13:22
      +1

      Если проверяется локально (через файлы в /etc/letsencrypt/....) - то вот этот каталог и есть "база" своего рода, и это showcert и делает (не используя сеть). Не самая быстрая база, согласен, но оптимизировать скрипт, который работает три секунды, да еще и фоном по крону - не слишком острая потребность. А если держать отдельную базу - то надо ее держать в соответствии, отслеживать все новые создания-удаления - сложно, и +1 точка отказа.


      1. ifap
        16.08.2022 13:47

        Я скорее про принцип: push вместо pull. Получен сертификат - о нем рапортуется в базу. А не скрипт регулярно опрашивает сервера: или ви таки получили новый серт?


        1. baldr
          16.08.2022 13:53
          +1

          Бывает форс-мажор: сервер сдох, восстановили вчерашний из бэкапа. А сертификат там еще старый, хотя в базе написано что новый.


          1. ifap
            16.08.2022 14:02

            Логично.


  1. baldr
    16.08.2022 13:11

    Автор молодец и затея, конечно, полезная. В базу занести, кронтаб настроить, напоминалку настроить - это все тоже нужно, но проверять не помешает.

    Однако, на фоне недавней статьи про "вымогатель" хочется напомнить, что предлагается установить на сервер незнакомый пакет, запустить его, практически, под root-правами (ну или кто там у вас владеет правами на эти файлы) и скормить ему все сертификаты с ключами на сервере. Я пробежался глазами по исходнику в гитхабе - вроде все невинно. Но хз что там в PyPI и что будет через час с новой версией.

    (просто напоминание о здоровой паранойе, автор не примите лично)


    1. xenon Автор
      16.08.2022 14:07
      +2

      Понимаю :-). И в pypi может новая версия любая оказаться, и в git. Сам параноик.

      В целом с showcert все просто и безопасно - ему "ничего такого" не требуется:

      1. Он не пишет файлы (даже вот для сохранения сертификата используется перенаправления stdout)

      2. Он работает с сертификатами (они публичные, раздаются всему миру), но не с приватными ключами.

      Так что, заизолировать можно как угодно. Пример заведомо безопасного использования:

      # sudo -u nobody showcert habr.com 
      Names: *.habr.com habr.com
      notBefore: 2021-11-12 00:00:00 (277 days old)
      notAfter: 2022-12-12 23:59:59 (118 days left)
      Issuer: C=GB ST=Greater Manchester L=Salford O=Sectigo Limited CN=Sectigo ECC Domain Validation Secure Server CA
      
      # sudo -u nobody showcert habr.com -o pem -c > /tmp/habr-fullchain.pem
      # sudo -u nobody showcert /tmp/habr-fullchain.pem 
      Names: *.habr.com habr.com
      notBefore: 2021-11-12 00:00:00 (277 days old)
      notAfter: 2022-12-12 23:59:59 (118 days left)
      Issuer: C=GB ST=Greater Manchester L=Salford O=Sectigo Limited CN=Sectigo ECC Domain Validation Secure Server CA
      

      Безопасен как юзер nobody под sudo! :-)

      А вот с letsencrypt - чуть сложнее - он хранит и сертификат и ключ рядом - в /etc/letsencrypt/archive/*/. И даже сертификат - world readable (0644), а ключ, как и полагается, 0600. Но сам каталог arсhive - доступен только для рута :-(. Поэтому, или ставить +x на каталоги, чтобы проверять от юзера, или использовать от рута.

      Безопасный воркэраунд для параноиков - скопировать все fullchain.pem куда-нибудь в /tmp и проверять от nobody.


  1. NAI
    16.08.2022 13:41

    Простой приятный способ проверить, что все LetsEncrypt сертификаты еще свежи:

    # showcert :le -qw/etc/letsencrypt/live/example.com/fullchain.pem expires in 19 days

    По моему, скромному мнению, не надо так.

    Лучше чекать именно то что отдает сервис (для примера):

    curl -Iv https://habr.com 2>&1 | grep "expire date" |  дальше по вкусу awk и прочее

    Т.к. в этом случае вы проверяете именно то что получит пользователь. Чекая /etc/letsencrypt/live/example.com/fullchain.pem вы проверяете валидность файла.. но не то что отдает NGINX\Apache\Node\etc.

    А что если LE оставили, но сервис перевели на ZeroSSL или вообще wildcard вставили? Или (ну вот так случилось) доступ к каталогам с сертификатами закрыли всем кроме рута\скрипту проверки. Или клиент\админ закрыл сайт через cloudflare и выпускает серт через него...


    1. baldr
      16.08.2022 13:54

      Кстати, да. А еще можно поменять файл сертификата, но забыть перезагрузить nginx, чтобы он его перечитал.


    1. xenon Автор
      16.08.2022 15:19
      +1

      Согласен, внешняя проверка больше случаев покрывает. Ну и вместо curl + grep + awk я бы сделал showcert habr.com -qw 20 :-)


      1. NAI
        16.08.2022 21:37

        Сделать то вы сделаете, только следующая проверка должна быть о том, что сайт отдает нужную страничку (не 50*\не 40*\не дефейснут) т.е. что-ндь в духе:

        curl -L https://habr.com 2>&1 | grep "habr-version"

        Т.е. курл... ну и нафига вам два инструмента, если можно использовать один?


        1. xenon Автор
          17.08.2022 01:05

          Эту проверку curl замечательно сделает. Но как им проверить сертификат на pop3 или smtp сервере, или посмотреть серт из файла и как им проверить что сертификат не на грани экспирейшна?


          1. NAI
            17.08.2022 10:20

            Так мы же вроде определились, что проверять файл немного бессмысленно и надо чекать конечный сервис

            Что касается почты. Допустим у вас нет веб-морды (хотя в 2022 это странно), допустим у вас там чистый МТА, для рассылок, так в чем проблема:

            curl smtps://smtp.gmail.com:465 -v

            добавляем grep бла-бла-бла if expire date < date +3d do echo error и все становится шоколадно (синтаксис поправьте сами)

            Почему я топлю за curl - он есть везде из коробки и не требует прав на установку. Запомнить надо ровно два ключа -Iv и 2>&1. И то последнее не ключ а перенаправление вывода. То что grep и awk сложны... ну вы же наверное и логи как-то парсите и там те же греп/авк...так что знать их все равно придется.


            1. xenon Автор
              17.08.2022 11:26

              проверять файл немного бессмысленно
              Смотря что нам хочется сделать. Если нам интересно что в файле - то только это и имеет смысл. Если мониторинг сервиса (проверяем действующий эффективный сертификат) - то да, надо смотреть, что сервис предоставляет. Но в жизни же есть разные задачи.

              Допустим у вас нет веб-морды (хотя в 2022 это странно),
              Более вероятны могут быть другие причины. Например, вебморда есть, но на другом сервере. Или есть, но у нее сертификат на mail.example.com, а у почтовика может быть на mx.example.com (вполне разумная схема). Так что, заменить проверку почтового сертификата проверкой https'ного может и не выйти.

              curl smtps://smtp.gmail.com:465 -v
              А можете подобным образом проверить сертификат на pop.yandex.ru:110 или
              gmail-smtp-in.l.google.com:25 ? Мне кажется, нет - потому что это потребует уже STARTTLS, который curl не умеет (Но благодаря вам, я сейчас удивился, что curl умеет письма слать... куда мир катится? ). Тут нужен уже starttls, как в openssl или showcert.

              синтаксис поправьте сами
              А отчего вы не написали его? :-) Это возможно, конечно, но нужно немного голову поломать, время потратить. Да и задачка не столь уж тривиальная, в красивый, простой, понятный one-liner может уже и не поместиться. А через две недели, вы забудете, как это сделали и где лежит тот скрипт, и над аналогичной задачей снова придется думать заново, распарсивая даты из одного формата в другой. Если делать решение один раз и на века - можно и потратить на это время, но если нужно быстро и просто - то над тем, как это сделать через showcert даже и думать не надо, задача решается со скоростью печатания короткой команды, несколько секунд.

              Curl хорош и стандартен, тут я с вами согласен, и много что можно делать. Например, вот для частного случая проверки, что сертификат действующий на TLS порту (smtps, https) - он вполне себе удобен (пара ключей - не проблема). Может быть, кстати, что существует какой-то простой почтовый клиент, скажем, fetchmail или аналог, которые могут и для pop3/imap выдать основную информацию о сертификате. Но зачем сложно, если можно просто? Без showcert можно выжить, я не спорю (сам же как-то обходился вот), но мне кажется, с ним проще и быстрее. Мелкая задача "посмотреть-проверить сертификат" возникает и тут же решается, над ней вообще не приходится думать, гуглить, смотреть заметки, тратить хоть какое-то время на нее.


              1. NAI
                17.08.2022 16:24

                Но в жизни же есть разные задачи. ...

                А можете подобным образом проверить сертификат на pop.yandex.ru:110 или gmail-smtp-in.l.google.com:25 ?

                Очень хочу услышать историю о том как потребовалось ковырять LE'шный серт. Вы же в статье про LE говорите, так ведь.

                А отчего вы не написали его? :-)

                Сложно писать с мобилки код сидя на совещании, но раз вы просите:

                #!/bin/bash
                TESTDATE=$(date "+%d-%b-%Y" --date="2 weeks")
                CURLDATE=$(curl smtps://smtp.gmail.com:465 -v 2>&1 | grep "expire date" | awk {'print $5 "-" $4 "-" $7}')
                
                if [[ $(date -d $TESTDATE +%s) < $(date -d $CURLDATE +%s) ]];
                then
                  echo "It's ok!"
                else
                  echo "ERROR!!!"
                fi

                Хотя, по-моему, с такой задачкой должен справляться джун-админ минут за 15, ну максимум 20. Свернуть в однострочник думаю опять таки сможете сами.

                И да мы тут в контексте проверок, проверки очевидно запускаются с мониторинга... зачем их куда-то таскать? Положил в гит пусть лежит... по-моему все так делают.


                1. mc2
                  17.08.2022 23:32

                  последний Иф можно вообще чуть подменить для удобства:

                  [[ $(date -d $TESTDATE +%s) > $(date -d $CURLDATE +%s) ]] && echo "ERROR!!!"


  1. mc2
    17.08.2022 00:54
    -2

    Тег "я пиарюсь" пропущен?)


    1. xenon Автор
      17.08.2022 02:15
      +2

      Не знаю. Это не коммерческий проект, а опен-сорсный, скорее обзор на утилиту. Мне кажется, "Я пиарюсь" больше для немного другого. Хотя, вот посмотрел статьи которые там, и вообще не понимаю, о чем они - на пиар своих коммерческих-некоммерческих проектов-сайтов вообще не похожи, но в том хабе.

      По крайней мере пару лет назад один мой пост был распубликован за "рекламу" и в переписке с администрацией они пояснили, что стоило дать ссылку на гитхаб, тогда бы было лучше. (иначе выглядит как реклама). Сейчас вот ссылка есть и вроде все норм.


      1. mc2
        17.08.2022 23:26

        Извините, если Вы восприняли это в негативном ключе. Такого не было и в мыслях.

        Имхо разницы опен-соурс или коммерческий нет. И там, и там нужен пиар, что бы развивать/развиваться. Коммерческий - это продажа продукта, не коммерческий - это "продажа себя".

        PS: на проектах у меня подобных "улучшайзеров" за десятки наверное, для ssl в том числе, но они нужны лишь тогда, когда это действительно нужно, т.к. экономит время и/или упрощает процесс.