UMGUM.COM (лучше) 

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

24 марта 2017  (обновлено 19 сентября 2018)

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

"Let’s Encrypt" от ISRG - простой и удобный HTTPS.
"Let’s Encrypt" от ISRG - простой и удобный HTTPS.

Случилось чудо - в конце 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.

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

# /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" норовит самостоятельно обновиться, проверяя наличие свежей версии на сайте разработчиков, и жалуется на нехватку прав для изменения системных параметров (а при наличии таковых нежелательным образом меняет структуру привилегий) - так что следует обязательно использовать его с ключом "--no-self-upgrade".

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

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

Настройка web-сервера.

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

Создаём локальную директорию, которая доступна для чтения 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

Отдельно описываем виртуальную ссылку с зарезервированным ISRG именем для web-сервера, которую связываем с локальной директорией для валидационных файлов:

# vi /etc/nginx/letsencrypt.conf

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

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

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

server {
  listen 80;
  server_name example.net;

  # Возможный блок перехвата трафика HTTP и перенаправления его в HTTPS
  location / {
    rewrite ^ https://$host$request_uri permanent;
  }

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

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

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

Прежде чем приступать к запросу и получению сертификатов как таковых настоятельно рекомендую проверить корректность настройки 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

# Задаём используемый тип аутентификации
authenticator = webroot

# Указываем тип соединения обмена данными при аутентификации
preferred-challenges = http

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

# Отключаем автоматическое самообновление утилиты, производимое по умолчанию при каждом её запуске
no-self-upgrade

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

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

# sudo -u certbot /opt/eff.org/certbot/venv/bin/certbot --config /etc/letsencrypt/cli.ini certonly -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

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

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

....
server {
  listen  443 ssl;
  server_name example.net;
  ....

  # Рекомендуемые обобщённые настройки протокола
  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;
  ....
}

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

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

Иногда 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-сервису перечитать конфигурацию
nginx -s reload

exit ${?}

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

# vi /etc/crontab

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

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


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


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