Получение LetsEncrypt wildcard сертификата

По следам статьи с сайта — https://www.umgum.com/letsencrypt-wildcard-bind9
Я только актуализировал информацию и оставил только один DNS.

Для автоматического получения wildcard сертификата используемый ACME-клиент (в данном случае Certbot) запрашивает у сервера Let’s Encrypt уникальную строку-идентификатор, которую любым способом необходимо разместить в специальной TXT-записи нижеследующего формата, чтобы проверяющий сервер Let’s Encrypt мог считать её и удостовериться, что мы владеем или управляем указанным DNS-сервером:

_acme-challenge.example.net. 120 IN TXT "Sg0...oLc" 

Все вышеуказанные действия подразумевают под собой ручное редактирование зоны, что в условиях наличия нескольких серверов DNS представляет большую трудоёмкость, да и ручное обновление сертификатов рано или поздно приведёт к истечению срока действия текущего.

Поэтому проще всего использовать дополнительно устанавливаемый certbot-плагин «dns-rfc2136«, автоматизирующий процедуры получения секретного ключа, публикующий его и удаляющий DNS-запись после завершения запроса, область действия которого, как правило, достаточно просто ограничивается настройками NS-сервера, как такового.
Плагин «dns-rfc2136» взаимодействует с DNS-сервером посредством протокола «Dynamic DNS (DDNS)» с подписанием команд посредством «Transaction SIGnature (TSIG)». Не все DNS-серверы поддерживают эту связку, но Bind9 в этом плане полностью функциональный.

Для начала подготовим необходимые файлы и настройки на DNS-сервере

ОС: Ubuntu
ПО: Certbot, bind9

Сгенерируем TSIG-ключ для подписания транзакций от ACME-приложений

tsig-keygen -a hmac-sha512 letsencrypt-example.net > /etc/bind/tsig.key

, где
tsig-keygen — утилита, входящая в состав bindutils при установке сервера bind9,
-a — тип алгоритма генерации,
hmac-sha512 — сам алгоритм,
letsencrypt-example.net — просто имя ключа. Его можно задать любым.

Сгенерированный ключ пишется в файл /etc/bind/tsig.key, содержимое которого примерно такое

key "letsencrypt-example.net" {
    algorithm hmac-sha512;
    secret "INVc+PYj...sF/USw==";
};

Защищаем файл от просмотра другими пользователями

chown bind:bind /etc/bind/tsig.key
chmod 640 /etc/bind/tsig.key

Включаем файл ключа в конфигурацию Bind9. Главное, чтобы ключ был описан вне пределов параметра options . Лучше описать его в файле named.conf

nano /etc/bind/named.conf
...
include "/etc/bind/tsig.key"; 
...

Использование протокола DDNS, посредством которым Certbot подключается и оперирует сущностями Bind9 проявляет в работе последнего неприятную особенность — при внесении изменений в доменную зону таковые вначале записываются в автоматически создаваемый файл журнала транзакций «*.jnl», которые минут через пятнадцать вливаются в оригинальный конфигурационный файл зоны, перезаписывая его с форматированием возможно кардинально отличающимся от исходного. Это неприемлемо в случае поддержания DNS-сервиса ручными правками, так что для тех доменов, для которых нужно запрашивать wildcard-сертификаты «Let`s Encrypt», будет лучше создавать выделенные для ACME-взаимодействий конфигурационные файлы доменной зоны:

В файле описания местоположения доменных зон пишем

nano /etc/bind/named.conf.local
...
// Выделенная для взаимодействия с сервисами "Let`s Encrypt" доменная зона
        zone "_acme-challenge.example.net" IN {
            type master;
            file "/var/lib/bind/db._acme-challenge.example.net";
            check-names ignore;

        // Разрешаем предъявителю TSIG-ключа вносить изменения строго определённого характера
            update-policy {
                grant letsencrypt-example.net name _acme-challenge.example.net. TXT;
            };

       };
...

, где
указывается файл отделённой зоны для продления сертификатов. Файл располагается не там, где основное описание доменных зон, а по адресу /var/lib/bind, потому что в Ubuntu из-за политики AppArmor, указанной в файле /etc/apparmor.d/usr.sbin.named описано, что для исполняемого файла named запрещено писать в /etc/bind/, но можно в /var/lib/bind/
В поле update-policy указывается, что только ключ с именем letsencrypt-example.net может менять TXT записи в зоне _acme-challenge.

В файл отделённой доменной зоны помещаются стандартные записи

nano /var/lib/bind/db._acme-challenge.example.net
$TTL 3600
_acme-challenge.example.net. IN SOA ns.example.net. root.example.net. (
                        2022121501      ; Serial
                               900      ; Refresh
                                60      ; Retry
                             86400      ; Expire
                               900 )    ; Negative Cache TTL
@                                 IN NS  ns.example.net.

Проверяем файл зоны

named-checkconf /etc/bind/named.conf
named-checkzone _acme-challenge.example.net /var/lib/bind/db._acme-challenge.example.net

zone _acme-challenge.example.net/IN: loaded serial 2022121525
OK
systemctl restart bind9

Теперь когда на DNS-сервере подготовлены файлы зоны, ключа и указана новая зона, можно приступить к настройке на стороне сервера, где установлен Certbot.

Устанавливаем плагин certbot-dns-rfc2136

apt install python3-certbot-dns-rfc2136

Настраиваем плагин.
Подготовим TSIG ключ, который был сгенерирован на DNS-сервере

nano /etc/letsencrypt/ns.example.net-rfc2136.ini
# (обязательно указывать IP-адрес, а не FQDN целевого NS-сервера!)
dns_rfc2136_server = 192.168.1.1
dns_rfc2136_name = letsencrypt-example.net
dns_rfc2136_secret = INVc+PY...LsF/USw==
dns_rfc2136_algorithm = HMAC-SHA512

,где
dns_rfc2136_server — IP сервера, на котором установлен Bind9,
dns_rfc2136_name — имя ключа, который указывался в файле tsig.key,
dns_rfc2136_secret — секрет, который так же указывался в файле ключа tsig.key.
dns_rfc2136_algorithm — алгоритм шифрования ключа.

Защищаем файл настройки от просмотра другими пользователями.

chmod 640 /etc/letsencrypt/ns.example.net-rfc2136.ini

Проверяем, что certbot корректно отрабатывает
Запускаем его с параметром —dry-run

certbot certonly --dry-run --dns-rfc2136 --force-renewal \
--dns-rfc2136-propagation-seconds 10 \
--dns-rfc2136-credentials /etc/letsencrypt/ns.example.net-rfc2136.ini \
--server https://acme-v02.api.letsencrypt.org/directory --email hostmaster@example.net \
--agree-tos --no-eff-email -d "example.net" -d "*.example.net" 

, где —dns-rfc2136 — тип аутентификации через плагин dns-rfc2136,
—dns-rfc2136-propagation-seconds — количество секунд для ожидания создания и появления TXT записей, чтобы сервер Let’s Encrypt смог их увидеть,
—dns-rfc2136-credentials — ini файл настроек

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

certbot certonly --dns-rfc2136 --force-renewal --dns-rfc2136-propagation-seconds 10 \
--dns-rfc2136-credentials /etc/letsencrypt/ns.example.net-rfc2136.ini \
--server https://acme-v02.api.letsencrypt.org/directory --email hostmaster@example.net \
--agree-tos --no-eff-email -d "example.net" -d "*.example.net" 

Команда запишет необходимые настройки в файл /etc/letsencrypt/renewal/example.net.conf и получит новые сертификаты.
Для последующего продления можно использовать команду certbot renew

Полученные сертификаты можно использовать с любимым веб-сервером. Ну и занести в крон. Или в таймеры systemd. Кому как нравится.

Список использованных источников:

Подписаться
Уведомить о
guest

2 комментариев
Новые
Старые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Thomas Krichel
9 месяцев назад

Thank you so much. This works great in general. Two comments

(1) it may be good to remind scatterbrained readers that they also have to set the _acme zone for the secondaries they may run. I certainly for
(2) if you run this for several domains, can you reuse the key? In that case your key name should not depend on the zone you are currently configuring. So could it be
key «letsencrypt» {
  algorithm hmac-sha512;
  secret «INVc+PYj…sF/USw==»;
};