Всем привет!
В этой статье я опишу как мы решали проблему централизованного обновления сертификатов Let's Encrypt и управления инфраструктурой с помощью ansible.
В нашем решении мы будем использовать:
- ansible
- rsync, rsyncd
- inotify, incron
- certbot
- nginx
Я предложу два варианта архитектуры, при которой наше решение может быть полезным. В свою очередь вы можете в комментариях предложить свои варианты.
Вариант 1: У вас есть несколько frontend серверов с public ip (к примеру 3), обслуживающих несколько доменов. Эти домены могут добавляться/удаляться. Чтобы не следить за каждым из frontend серверов — удобнее это сделать на одном letsencrypt server
'е:
Вариант 2: У вас есть только один сервер с public ip, а сертификаты вам нужны на серверах внутри сети:
Описание ролей ansible
Репозиторий с ролями доступны по ссылке.
В репозитории находится 4 роли:
- nginx-simple
Устанавливает на все хостыnginx
и копирует базовые конфиги. Сама по себе роль не запускается из playbook. Она запускается по meta зависимости из других ролей. - letsencrypt-server
Настраиваетrsyncd
на хостеletsencrypt server
. В meta зависимостях имеет рольnginx-simple
. Соответственно, сначала установитсяnginx
, а потом проиграется рольletsencrypt server
. - incron
Устанавливает необходимые пакеты дляincron
и скопирует базовый конфиг. Роль так же не запускается на прямую как иnginx-simple
. - front
В meta зависимостях имеет ролиincron
иnginx-simple
. После них рольfront
копирует необходимые для example.com конфигиnginx
, добавляет задачу вcron
забирать новые сертификаты сletsencrypt server
и задачу вincron
проверять изменения файлов и выполнять хукnginx -s reload
Перейдем к практике:
Исходная конфигурация
Изначально у нас имеются:
- 1 сервер для централизованного выписывания SSL сертификата (
letsencrypt server
) - 1 или более публично доступных серверов с nginx (
front
)
На всех серверах установлена Ubuntu 16.04.
Установка и настройка nginx
Для начала установим на все хосты nginx из общей роли nginx-simple
и раскидаем общие для всех хостов конфиги nginx (nginx.conf, параметры ssl, пути к сертификатам, etc).
Для letsencrypt server'а в шаблоне .../site-available/default.conf
папка .well_known
будет находиться в /var/www/
:
{% if letsencrypt_server %}
location /.well-known {
root /var/www/;
}
Для сервера/серверов группы front
, так как папка .well_known
используется не только для получения сертификатов, но и для другого ПО, мы импортируем в конфиг example.conf
letsencrypt-proxy.conf
и nginx будет искать папку локально на сервере front, используя дерективу try_file
:
{% if nginx_proxy_well_known %}
try_files $uri $uri/ @letsencrypt;
{% endif %}
Конфиги для домена заполнятся в зависимости от переменных из inventory. В репозитории это домен example.com
Так же, в зависимости от переменной letsencrypt_server
, роль nginx-simple
установит на letsencrypt server certbot
и добавит cron task на обновление сертификатов.
Получение сертификата
Так как мы решали эту задачу до появления wildcard сертификата от Let's Encrypt, мы рассмотрим оба варианта получения сертификата.
На сервере letsencrypt server выполняем:
certbot certonly --agree-tos -d example.ru --webroot -w /var/www/
Если доменов больше одного — дописываем последующие, используя ключ -d
.
Для получения wildcard сертификата нам нужно будет добавить в DNS TXT записи. На текущий момент это единственный вариант получения такого сертификата:
certbot certonly --agree-tos -d example.ru -d *.example.ru --preferred-challenges dns --manual --server https://acme-v02.api.letsencrypt.org/directory
Certbot напишет какие TXT записи вам нужно будет добавить.
Обновление сертификатов
Сертификаты мы получили, осталось настроить копирование их на front сервер/сервера. Для этого мы настроим rsyncd
на сервере letsencrypt с правами на чтение для ограниченого списка ip адресов:
hosts allow = {{ hosts_allow }}
hosts deny = *
list = true
use chroot = no
[cert]
path = /etc/letsencrypt/live/
uid = root
gid = root
read only = true
Каждые 5 минут cron task с серверов front будет проверять обновились ли сертификаты и забирать их. Т.к. сертификаты ротируются, в папке /etc/letsencrypt/live/{{ domain }}
лежат симлинки. Добавим ключ -L
чтобы вытаскивать оригиналы файлов:
/usr/bin/rsync -zavL --chmod=D0750,F640 --delete rsync://{{ hostvars['letsencrypt-server'].ansible_eth0.ipv4.address }}/cert /etc/letsencrypt/live/
Хук для nginx
Мы настроили nginx, получили сертификаты, забрали их на front сервер. Осталось определить, что файлы в папке /etc/letsencrypt/live/{{ domain }}
изменились и выполнить хук nginx -s reload
В этом нам поможет подсистема ядра linux inotify
и демон incron
. Подробнее о них можно прочесть тут.
Роль incron
установит нужные пакеты, а из шаблона роли front
добавится задача на мониторинг сертификатов и нужный хук:
/etc/letsencrypt/live/{{ domain }}/ IN_CREATE,IN_DELETE,IN_MODIFY,IN_MOVED_TO nginx -s reload
В заключение
Мы постарались подробно описать весь процесс установки и настройки, а т.к. все описано в плейбуках ansible — статья получилась очень компактной. Как любят часто говорить — "чуть больше 100 строчек кода". На вопросы, критику и замечания с удовольствием ответим в комментариях.
Автор: Asten