UMGUM.COM 

Let‘s Encrypt ( Настройка подсистемы получения и автоматического обновления криптографических сертификатов X.509 для SSL/TLS шифрования в протоколе HTTPS. )

24 марта 2017  (обновлено 9 января 2020)

OS: "Linux Debian 7/8/9/10", "Linux Ubuntu 14/16/18 LTS", "Linux Fedora 23/24/25".
Application: "Certbot client v.0.12/1.0" for "Let`s Encrypt" (on Python), "Nginx".


Случилось чудо - в конце 2016 года группой "Internet Security Research Group (ISRG)" был запущен сервис простой автоматической и бесплатной выдачи криптографических сертификатов X.509 для SSL/TLS шифрования (HTTPS) под названием "Let’s Encrypt". Зачиналось всё с внутреннего инструментария Mozilla, а сейчас в проекте полноценно участвуют Linux Foundation, Google, Microsoft, Apple, Akamai, Cisco и ещё и ещё. Задачи идентификации сайта в проекте не ставится - цель в обеспечении технической возможности шифрования соединения между web-браузером пользователя и web-сервисом для исключения вмешательства в процесс обмена данных, несанкционированного доступа к ним или подмены таковых. Сертификаты X.509 выдаются всего на три месяца и их, естественно, приходится непрерывно обновлять, запрашивая новые - это составляющая базовой стратегии, направленной в сторону развития технологий защиты данных с максимальной составляющей автоматизации, полностью исключающей ручной труд по валидации и проверке предоставляемых пользователю сведений о защищаемом web-ресурсе.

Первичное получение и последующее автоматическое обновление SSL/TLS-сертификатов для web-сайтов удобно осуществлять с помощью специально для этого предназначенного набора утилит "Certbot client", рекомендуемого ISRG. Разработка ведётся здесь: https://github.com/certbot/certbot , а получить в адаптированном для целевой операционной системы виде это программное обеспечение можно тут: https://certbot.eff.org/

На сайте разработчиков представлено обилие выбора реализаций для разных современных дистрибутивов Linux, но на практике нет смысла выискивать что-то подходящее конкретно под целевую операционную систему, а вполне достаточно загрузить инсталлятор "certbot-auto", представляющий собой обёртку для "certbot" как такового и предназначенный для удовлетворения системных зависимостей (вроде установки и обновления необходимого "Python v3" и "OpenSSL v1") и загрузки набора Python-скриптов самого "certbot". По идее, "certbot-auto" нужно запускать один раз для установки "certbot" и возвращаться к этой процедуре лишь при плановом обновлении ПО web-сервера.


Установка, первичная настройка и проверка

Набор утилит "Certbot client" по умолчанию устанавливается в директорию "/opt/eff.org/certbot/venv", определяемую переменной окружения "$VENV_PATH" в BASH-скрипте "certbot-auto" - при желании её можно переопределить, но я ничего против этого месторасположения не имею:

# mkdir -p /opt/eff.org/certbot-auto
# cd /opt/eff.org/certbot-auto
# wget https://dl.eff.org/certbot-auto
# chmod a+x ./certbot-auto

Запускаем инсталляцию:

# cd /opt/eff.org/certbot-auto
# ./certbot-auto --install-only

Типичный вывод результатов успешной установки:

Bootstrapping dependencies for Debian-based OSes...
....
Fetched 323 kB in 2s (122 kB/s)
....
The following additional packages will be installed:
  libssl1.0.0 python-minimal zlib1g-dev
....
Creating virtual environment...
Installing Python packages...
Installation succeeded.
Certbot is installed.

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

....
To use the Apache Certbot plugin, augeas needs to be installed from wheezy-backports.
Would you like to enable the wheezy-backports repository [Y/n]? n
....

Проверяем, запустится ли приложение:

# /opt/eff.org/certbot/venv/bin/certbot --version

На серверах я предпочитаю по возможности удерживать каждую подсистему в изолированном, созданном специально для него пользовательском окружении - также поступим и сейчас:

# useradd --system --home-dir /opt/eff.org/certbot --shell /bin/false --gid www-data certbot

Передаём во владение свежесозданного специализированного пользователя директорию с его программным обеспечением:

# chown -R certbot:root /opt/eff.org/certbot
# chmod -R o-rwx /opt/eff.org/certbot

Заготовим место для хранения настроек и сертификатов:

# mkdir -p /etc/letsencrypt
# chown -R certbot:www-data /etc/letsencrypt

Создаём директории для сохранения промежуточных данных и журналов событий:

# mkdir -p /var/lib/letsencrypt
# chown -R certbot:root /var/lib/letsencrypt

# mkdir -p /var/log/letsencrypt
# chown -R certbot:root /var/log/letsencrypt

"Certbot client" поддерживает автоматизацию получения сертификатов путём интеграции с web-серверами через соответствующие плагины, но для понимания сути происходящего есть смысл настроить всё непосредственной правкой конфигурационных файлов, а запускать утилиту в режиме "webroot" (с размещением временных валиадционных данных в файловой системе сайта, для которого запрашивается сертификат).

Создаём локальную директорию, которая доступна для чтения web-серверу, куда утилита "Certbot client" будет укладывать временные валидационные файлы, размещая заодно там тестовую HTML-страничку:

# mkdir -p /var/www/letsencrypt/.well-known/acme-challenge/
# echo "Let\`s Encrypt" > /var/www/letsencrypt/.well-known/acme-challenge/index.html
# chown certbot:www-data -R /var/www/letsencrypt

При каждом запуске "Certbot client" норовит самостоятельно обновиться, проверяя наличие свежей версии на сайте разработчиков, и жалуется на нехватку прав для изменения системных параметров (а при наличии таковых нежелательным образом меняет структуру привилегий) - так что следует обязательно использовать его с ключом "--no-self-upgrade".

Сразу можно проверить, нет ли на борту каких-нибудь сертификатов, возможно загруженных ранее:

# sudo -u certbot /opt/eff.org/certbot/venv/bin/certbot --no-self-upgrade certificates

Предварительная настройка web-сервера "Nginx".

Отдельно описываем виртуальную ссылку с зарезервированным ISRG путём к ресурсам "/.well-known/acme-challenge/" для web-сервера "Nginx", которую связываем с локальной директорией для валидационных файлов:

# mkdir -p /etc/nginx/snippets
# vi /etc/nginx/snippets/letsencrypt.conf

location ^~ /.well-known/acme-challenge/ {
  default_type "text/plain";
  root /var/www/letsencrypt;
  break;
}

В описании каждого сайта, которому требуется поддержка "Let`s Encrypt", внедряем заготовленный блок конфигурации ресурсов:

# vi /etc/nginx/sites-enabled/example.net

server {
  listen 80;
  server_name example.net;

  # Возможный блок перехвата трафика HTTP и перенаправления его в HTTPS
  location ~* ^/(?!(\.well-known)) {
    rewrite ^ https://$host$request_uri permanent;
  }

  # Включение конфигурации директории верификации Let`s Encrypt
  include /etc/nginx/snippets/letsencrypt.conf;
}

Проверяем синтаксическую корректность конфигурации и указываем web-серверу её принять:

# nginx -t
# /etc/init.d/nginx reload

Вариант конфигурации для "Apache2" рассматривается отдельно.
Вариант конфигурации для "Lighttpd" рассматривается отдельно.
Вариант конфигурации для комбайна "GitLab" рассматривается отдельно.
Вариант конфигурации для почтового сервера "Zimbra" рассматривается отдельно.

Прежде чем приступать к запросу и получению сертификатов как таковых настоятельно рекомендую проверить корректность настройки web-сервера - элементарно удостовериться доступности специально для этого размещённого ".well-known/acme-challenge/index.html" из интернета. На практике в каждой второй конфигурации приходится ещё донастроить web-сервисы, чтобы схема сработала как было задумано:

$ wget -nv -O - http://example.net/.well-known/acme-challenge/index.html

Настройка утилиты "Certbot client".

"Certbot client" складывает актуальные сертификаты в директорию "/etc/letsencrypt/live", а предыдущие в директорию "/etc/letsencrypt/archive". В специальной настройке современная версия клиента практически не нуждается - в первый раз сертификат запрашивается в ручном режиме с указанием параметров сайта, а в последующие запуски с указанием на необходимость обновления сертификатов скрипт будет перебирать все уже имеющиеся и обновлять их при необходимости.

Ряд неизменных параметров запуска утилиты есть смысл вынести в конфигурационный файл:

# vi /etc/letsencrypt/cli.ini

# Задаём адрес почтового ящика, который может быть использован для связи с сервисом
email = support@example.net

# Указываем месторасположение директории, используемой для временных верификационных файлов
# (используется при аутентификации посредством плагина "webroot")
webroot-path = /var/www/letsencrypt

# Отмечаем, что мы читали лицензионное соглашение и уже согласились с ним
agree-tos

# Отключаем автоматическое самообновление утилиты
no-self-upgrade

Первичный запрос сертификатов и применение их в web-сервисе.

Для каждого web-ресурса нужно осуществить первичный запрос сертификата:

# sudo -u certbot /opt/eff.org/certbot/venv/bin/certbot --config /etc/letsencrypt/cli.ini certonly --webroot --preferred-challenges http-01 -d example.net

Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.net
Using the webroot path /var/www/letsencrypt for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0005_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0005_csr-certbot.pem

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.net/fullchain.pem. Your cert will
   expire on 2017-06-19. To obtain a new or tweaked version of this
   certificate in the future, simply run Certbot again. To
   non-interactively renew *all* of your certificates, run
   "certbot renew"

В результате мы получаем примерно такую файловую структуру:

# tree -ug /etc/letsencrypt/live/

/etc/letsencrypt/live/
└── [certbot www-data] example.net
  ├── [certbot www-data] cert.pem -> ../../archive/example.net/cert1.pem
  ├── [certbot www-data] chain.pem -> ../../archive/example.net/chain1.pem
  ├── [certbot www-data] fullchain.pem -> ../../archive/example.net/fullchain1.pem
  ├── [certbot www-data] privkey.pem -> ../../archive/example.net/privkey1.pem
  └── [certbot www-data] README

Для полноты представлений о сути происходящего перед использованием сгенерированного "Certbot"-ом сертификата можно полюбопытствовать его параметрами:

# openssl x509 -text -noout -in /etc/letsencrypt/live/example.net/fullchain.pem

Certificate:
  Data:
    Version: 3 (0x2)
    Serial Number:
      03:c6:...:cf:fc
  Signature Algorithm: sha256WithRSAEncryption
    Issuer: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3
    Validity
      Not Before: Oct 15 03:19:15 2018 GMT
      Not After : Jan 13 03:19:15 2019 GMT
  Subject: CN=example.net
....

Теперь, когда SSL/TLS-сертификаты готовы, их можно применить в настройках web-сервиса. Для "Nginx" это делается примерно так:

# vi /etc/nginx/sites-enabled/example.net

....
# Перехват запросов к имени нежелательного формата и перенаправление к нужному
server {
  listen  443 ssl;
  server_name www.example.net;
  access_log off;
  error_log  off;
  location / {
    rewrite ^ https://example.net$request_uri permanent;
  }

  # Рекомендуемые обобщённые настройки протокола
  ssl on;
  ssl_dhparam          /etc/nginx/ssl/dhparam.pem;
  ssl_protocols        SSLv3 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers          AES256-SHA:RC4:HIGH:!aNULL:!MD5:!kEDH;
  ssl_prefer_server_ciphers on;
  ssl_session_cache    shared:SSL:30m;
  ssl_session_timeout  1h;

  # Сертификаты Let`s Encrypt
  ssl_certificate          /etc/letsencrypt/live/www.example.net/fullchain.pem;
  ssl_certificate_key      /etc/letsencrypt/live/www.example.net/privkey.pem;
  ssl_trusted_certificate  /etc/letsencrypt/live/www.example.net/chain.pem;
}

# Описание рабочего окружения доступного по HTTPS web-сайта как такового
server {
  listen  443 ssl;
  server_name example.net;
  ....

  # Рекомендуемые обобщённые настройки протокола
  ssl on;
  ssl_dhparam          /etc/nginx/ssl/dhparam.pem;
  ssl_protocols        SSLv3 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers          AES256-SHA:RC4:HIGH:!aNULL:!MD5:!kEDH;
  ssl_prefer_server_ciphers on;
  ssl_session_cache    shared:SSL:30m;
  ssl_session_timeout  1h;

  # Сертификаты Let`s Encrypt
  ssl_certificate          /etc/letsencrypt/live/example.net/fullchain.pem;
  ssl_certificate_key      /etc/letsencrypt/live/example.net/privkey.pem;
  ssl_trusted_certificate  /etc/letsencrypt/live/example.net/chain.pem;

  ....
}

Естественно, после изменения конфигурации web-сервера таковому необходимо дать указание перечитать настройки:

# nginx -t
# /etc/init.d/nginx reload

Вариант конфигурации для "Apache2" рассматривается отдельно.
Вариант конфигурации для "Lighttpd" рассматривается отдельно.
Вариант конфигурации для комбайна "GitLab" рассматривается отдельно.
Вариант конфигурации для почтового сервера "Courier Mail" рассматривается отдельно.
Вариант конфигурации для почтового сервера "Zimbra" рассматривается отдельно.

Иногда web-сервисы запускают от имени специализированного пользователя, вроде "nginx". В таком случае я включаю этого пользователя в группу "www-data", для унификации:

# usermod --append --groups www-data nginx

Автоматизация продления сертификатов.

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

# sudo -u certbot /opt/eff.org/certbot/venv/bin/certbot --config /etc/letsencrypt/cli.ini renew

Скриптом перебираются и обновляются все обнаруженные в директории утилиты "/etc/letsencrypt/" сертификаты, которым до истечения осталось меньше одного месяца. Можно обновить конкретный сертификат, указав его имя, но для автоматизации удобнее прогонять сразу все скопом. Так же удобно запускать утилиту в режиме тестирования, без применения изменений, с помощью ключа "--dry-run". Ключик "--force-renewal" велит обновить сертификаты немедленно, не дожидаясь условного порога в один месяц до истечения срока действия.

С учётом особой умности утилиты "Certbot client" автоматизация обновления сертификатов заключается в её элементарном регулярном запуске. Удобно создать отдельный скрипт, в котором отрабатывать команды использующим сертификаты приложениям перечитать и применить их:

# touch /opt/eff.org/cert-renew.sh
# chmod +x /opt/eff.org/cert-renew.sh
# vi /opt/eff.org/cert-renew.sh

#!/bin/bash

# Запускаем утилиту с указанием обновить имеющиеся сертификаты
sudo -u certbot /opt/eff.org/certbot/venv/bin/certbot --non-interactive --quiet --config /etc/letsencrypt/cli.ini renew

# Даём указание использующему сертификаты web-сервису перечитать конфигурацию
[ -x "$(command -v nginx)" ] && nginx -t > /dev/null 2>&1 && { nginx -s reload; }

exit ${?}

Вариант конфигурации для "Apache2" рассматривается отдельно.
Вариант конфигурации для "Lighttpd" рассматривается отдельно.
Вариант конфигурации для комбайна "GitLab" рассматривается отдельно.
Вариант конфигурации для почтового сервера "Courier Mail" рассматривается отдельно.
Вариант конфигурации для почтового сервера "Zimbra" рассматривается отдельно.

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

# vi /etc/crontab

....
# Certificates renew using Let`s Encrypt "Certbot client"
0 0  * * 2  root /opt/eff.org/cert-renew.sh &

Успешный полёт схемы более полутора лет - надеюсь, дальше будет только лучше.


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )