Централизованное обновление сертификатов Let’s Encrypt

в 7:40, , рубрики: Ansible, devops, inotify, LetsEncrypt, nginx, системное администрирование

letsencrupt server

Всем привет!

В этой статье я опишу как мы решали проблему централизованного обновления сертификатов Let's Encrypt и управления инфраструктурой с помощью ansible.

В нашем решении мы будем использовать:

  • ansible
  • rsync, rsyncd
  • inotify, incron
  • certbot
  • nginx

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

Вариант 1: У вас есть несколько frontend серверов с public ip (к примеру 3), обслуживающих несколько доменов. Эти домены могут добавляться/удаляться. Чтобы не следить за каждым из frontend серверов — удобнее это сделать на одном letsencrypt server'е:

Пример 1

Вариант 2: У вас есть только один сервер с public ip, а сертификаты вам нужны на серверах внутри сети:

Пример 2

Описание ролей 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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js