letsencrypt
Ansible роль для получения SSL сертификатов Let's Encrypt
Эта роль предназначена для запроса SSL сертификатов от Let's Encrypt, используя HTTP или DNS challenge для их ACME API.
Возможности:
- Устанавливает и настраивает certbot и вспомогательный скрипт для DNS challenge
- Поддерживает как HTTP, так и DNS challenge
- Для HTTP challenge поддерживаются плагины аутентификации
apache
,nginx
,standalone
иwebroot
- Для HTTP challenge поддерживаются плагины аутентификации
- DNS challenge использует отдельную зону только для токенов ACME challenge, что снижает риски безопасности от динамических обновлений
- Перезапуск служб при обновлении сертификата с использованием пост-хуков или пользовательской команды пост-хука
- Управление доступом к сертификатам с помощью специальной системной группы
Поддерживаемые дистрибутивы:
- Debian 11 (Bullseye)
- Debian 12 (Bookworm)
Тестировалось на:
- Debian 11 (Bullseye)
- Debian 12 (Bookworm)
- CentOS7
- Ubuntu 2204 (Jammy Jellyfish)
Роль выполняет следующее:
Когда letsencrypt_setup равно True (по умолчанию), эта роль будет:
- Устанавливать certbot
- Регистрировать учетную запись в Let's Encrypt
- Устанавливать необходимые файлы/ключи для DNS challenge
- Создавать системную группу 'letsencrypt'
Когда вызывается с заполненной переменной 'letsencrypt_cert':
- Запрашивает SSL сертификат через Let's Encrypt ACME API, используя либо HTTP challenge, либо DNS challenge
- По желанию устанавливает пост-хук для обновления сертификата (для перезапуска необходимых служб после этого)
- По желанию добавляет системных пользователей в группу 'letsencrypt', чтобы предоставить им доступ к сертификатам SSL и их закрытым ключам
Как это работает (примеры)
- Установка certbot
ansible-playbook site.yml -l localhost -t letsencrypt
- Создание сертификата через HTTP challenge и аутентификатор
webroot
(перезапуск службы 'apache2' при обновлении):ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub.example.org","domains":["sub.example.org"],"challenge":"http","http_auth":"webroot","webroot_path":"/var/www/sub.example.org","services":["apache2"]}}'
- Создание сертификата через DNS challenge (предоставление доступа к сертификатам пользователю 'Debian-exim', перезапуск служб 'exim4' и 'dovecot' при обновлении):
ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub2","domains":["sub2.example.org","sub2.another.example.org"],"challenge":"dns","services":["dovecot","exim4"],"users":["Debian-exim"]}}'
- Создание сертификата через HTTP challenge и аутентификатор
standalone
(повторное использование того же закрытого ключа при обновлении и выполнение пользовательского скрипта пост-хука при обновлении):ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub3","domains":["sub3.example.org"],"challenge":"http","http_auth":"standalone","reuse_key":True,"post_hook":"/usr/local/bin/cert-post-hook.sh"}}'
Ожидаемая структура переменной letsencrypt_cert
Переменная letsencrypt_cert
ожидается как словарь:
letsencrypt_opts_extra: "--register-unsafely-without-email"
letsencrypt_cert:
name: sub.example.org
domains:
- sub.example.org
challenge: http
http_auth: webroot
webroot_path: /var/www/sub.example.org
services:
- apache2
или:
letsencrypt_cert:
name: sub2
domains:
- sub2.example.org
- sub2.another.example.org
challenge: dns
services:
- dovecot
- exim4
users:
- Debian-exim
или:
letsencrypt_cert:
name: sub3
domains:
- sub3.example.org
challenge: http
http_auth: standalone
reuse_key: True
post_hook: "/usr/local/bin/cert-post-hook.sh"
letsencrypt_cert:
name: sub3
domains:
- sub3.example.org
challenge: http
http_auth: standalone
reuse_key: True
deploy_hook: "/usr/local/bin/cert-post-hook.sh"
Словарь поддерживает следующие ключи:
name
: имя сертификата [опционально]domains
: список доменов для сертификата [обязательно]challenge
: 'http' или 'dns' [обязательно]- для challenge 'http':
http_auth
: 'webroot', 'apache' или 'nginx' [опционально, по умолчанию 'webroot']- для http_auth 'webroot':
webroot_path
[опционально, по умолчанию '/var/www']
- для http_auth 'webroot':
- для challenge 'http':
services
: список служб для перезапуска в пост-хуке [опционально]reuse_key
: Повторное использование того же закрытого ключа при обновлении сертификата. 'True' или 'False' (по умолчанию 'False')post_hook
: Пользовательский пост-хук, который будет выполнен после попытки получить/обновить сертификат [опционально]deploy_hook
: Пользовательский деплой-хук, который будет выполнен после успешной попытки получить/обновить сертификат [опционально]renew_hook
: Пользовательский хук для обновлений, который будет выполнен один раз для каждого обновленного сертификата после обновления [опционально]users
: список пользователей для добавления в системную группу 'letsencrypt' [опционально]
Общие предварительные требования
Роль заботится о установке certbot и запросе SSL сертификатов, используя либо HTTP, либо DNS challenge. Она не устанавливает и не настраивает необходимую инфраструктуру (например, веб-сервер Apache или DNS сервер).
Роль протестирована только с Ansible 2.2. Нет гарантии, что она будет работать с более ранними версиями Ansible.
HTTP challenge
Требования:
- Доменное имя(я) запрашиваемого сертификата должно указывать на систему
- Для http_auth 'apache' на системе должен быть установлен (и настроен) Apache2
- Для http_auth 'nginx' на системе должен быть установлен (и настроен) NGINX
DNS challenge
Требования:
- DNS сервер с отдельной зоной, используемой только для ACME DNS challenge. Эта зона должна разрешать динамические обновления DNS (NSUPDATE) для TXT записей (см. ниже).
- CNAME записи для
_acme-challenge.sub.example.org
для всех доменных имен(ий) запрашиваемого сертификата должны указывать наsub.example.org._le.example.org
(внутри отдельной зоны для ACME DNS challenge). - Содержимое ключа обновления DNS и закрытые ключи DNS обновления должны быть доступны в переменных Ansible
letsencrypt_ddns_key
иletsencrypt_ddns_privkey
(предпочтительно внутри хранилища).
Эта роль устанавливает вспомогательный скрипт для DNS challenge в /usr/local/bin/certbot-dns-hook.sh
. Этот скрипт добавит токен валидации в TXT запись на sub.example.org._le.example.org
во время DNS challenge и удалит его после.
Поддержка подстановочных знаков с DNS challenge
Получение сертификатов с подстановочными знаками должно работать «из коробки» через DNS challenge.
Настройка bind9 для DNS challenge
(Другой вариант — использовать acme-dns сервер для этого)
Сгенерируйте ключ для динамических обновлений:
cd /etc/bind/keys
dnssec-keygen -a HMAC-SHA512 -b 512 -n USER _le.example.org_ddns_update
chown -R bind:bind /etc/bind/keys
Добавьте ключ в конфигурацию bind (например, в /etc/bind/named.conf.options
):
key "_le.example.org_ddns_update" {
algorithm hmac-sha512;
secret "...";
};
Создайте зону для динамических обновлений:
$ORIGIN .
$TTL 86400 ; 1 день
_le.example.org IN SOA ns1.example.org. postmaster.example.org. (
2017061501 ; серийный номер
86400 ; обновление (1 день)
3600 ; повтор (1 час)
2419200 ; срок действия (4 недели)
86400 ; минимальный (1 день)
)
NS ns1.example.org.
NS ns2.example.org.
TXT "v=spf1 -all"
и настройте ее в вашей конфигурации bind (например, в /etc/bind/named.conf.local
):
zone "_le.example.org" {
type master;
file "/etc/bind/zones/db._le.example.org";
update-policy { grant _le.example.org_ddns_update wildcard *._le.example.org. TXT; };
};
Формат для /etc/letsencrypt/keys/ddns_update.key
(из bind):
key "<key>" {
algorithm HMAC-SHA512;
secret "<key>";
};
Формат для /etc/letsencrypt/keys/ddns_update.private
:
Private-key-format: v1.3
Algorithm: 165 (HMAC_SHA512)
Key: <key>
Bits: AAA=
Создан: 20181017144534
Опубликован: 20181017144534
Активирован: 20181017144534
Значения переменных Ansible по умолчанию
# Выполнить шаг настройки; установить false для отключения
letsencrypt_setup: True
# Предоставить существующие учетные данные для копирования
letsencrypt_account: ""
# letsencrypt_account:
# hash: 1234567890abcdef1234567890abcdef
# id: 123456789
# creation_host: localhost
# creation_dt: 2020-12-13T13:12:00Z
# private_key:
# n: 1234
# e: 5678
# d: 90ab
# p: cdef
# q: 1234
# dp: 5678
# dq: 90ab
# qi: cdef
# kty: RSA
# Установить адрес электронной почты, связанный с учетной записью Let's Encrypt
letsencrypt_account_email: ""
# Аутентификатор по умолчанию для HTTP challenge ('webroot' или 'apache')
letsencrypt_http_auth: webroot
# Путь к веб-корню для аутентификатора 'webroot'
letsencrypt_webroot_path: /var/www
# Установить вспомогательный скрипт для DNS challenge и ключ обновления DNS
letsencrypt_dns_challenge: yes
# Настройки для динамических обновлений зоны DNS
# letsencrypt_ddns_server: ""
# letsencrypt_ddns_zone: ""
# letsencrypt_ddns_key: ""
# letsencrypt_ddns_privkey: ""
# Создание системной группы 'letsencrypt' для доступа к сертификатам
letsencrypt_group: yes
# Повторное использование закрытого ключа при обновлении сертификата?
letsencrypt_reuse_key: False
# Разрешить подмножество имен?
letsencrypt_subset_names: True
# Установить глобальные дополнительные параметры командной строки для certbot
letsencrypt_opts_extra: ""
# Установить путь для каталога letsencrypt (без завершающего "/" !!)
letsencrypt_directory: /etc/letsencrypt
Тестирование
В целях тестирования переменная letsencrypt_test
может быть установлена. Если она установлена в True, роль будет использовать тестовые серверы Let's Encrypt для создания учетной записи и получения сертификата.
Для разработки и тестирования роли мы используем Molecule и Vagrant/Github Actions. В локальной среде вы можете легко протестировать роль с помощью
molecule test
Лицензия
Эта Ansible роль лицензирована под GNU GPLv3.
Автор
Авторские права 2017-2019 systemli.org (https://www.systemli.org/)
ansible-galaxy install systemli/ansible-role-letsencrypt