AI Единый SSL, или Автоматизация Let's Encrypt на HAProxy

AI

Редактор
Регистрация
23 Август 2023
Сообщения
2 978
Лучшие ответы
0
Реакции
0
Баллы
51
Offline
#1
Привет, Хабр! На связи Алексей Холодаев из Cloud4Y. Наверняка вам знакома типичная архитектура — несколько бэкенд-серверов, один HAProxy на входе и куча поддоменов — app.example.com, api.example.com, admin.example.com. Классический подход к SSL заставляет вас либо покупать дорогой Wildcard-сертификат, либо мучительно поддерживать отдельные сертификаты для каждого поддомена на каждом бэкенде…

А что, если я покажу вам способ получше?

Давайте настроим получение и, что критично, полностью автоматическое продление одного SSL-сертификата от Let's Encrypt прямо на HAProxy. Этот единственный сертификат будет защищать все ваши поддомены сразу. Больше не нужно возиться с SSL на каждом бэкенде — весь трафик шифруется и расшифровывается на балансировщике, а до бэкендов идёт уже по защищённому внутреннему каналу.



В итоге вы получаете:


  • экономию — один бесплатный сертификат вместо множества


  • централизованное управление — весь SSL-трафик обрабатывается в одном месте


  • автоматизацию — система сама обновляет сертификаты, вам не нужно о них думать

Проблема в том, что «из коробки» Let's Encrypt и HAProxy не дружат. Стандартный процесс получения сертификата ломается, так как HAProxy не умеет обрабатывать специальные запросы от Let's Encrypt. Сегодня мы решим эту проблему раз и навсегда.

Наше решение — это продуманная маршрутизация в HAProxy


Нам нужно научить HAProxy распознавать «специальные» запросы от Let's Encrypt и перенаправлять их не на приложение, а на тот самый автономный сервер Certbot. При этом все остальные запросы должны идти своим обычным путем.

Шаг 1: Настройка HAProxy для работы с Let's Encrypt


Вот базовая конфигурация, которая решает проблему маршрутизации. Она перенаправляет запросы проверки от Let's Encrypt на сервер Certbot, а весь остальной трафик — на ваши бэкенды:

# Фронтенд работает только на порту 80
# Если обнаруживает запрос Let's Encrypt, использует бэкенд LE
# Иначе идёт в стандартный бэкенд для веб-серверов
frontend fe-scalinglaravel
bind *:80
# Проверяем URI на запросы Let's Encrypt
acl letsencrypt-acl path_beg /.well-known/acme-challenge/
use_backend letsencrypt-backend if letsencrypt-acl
default_backend be-scalinglaravel
# Бэкенд для Let's Encrypt
backend letsencrypt-backend
server letsencrypt 127.0.0.1:8888
# Обычный (стандартный) бэкенд
# для веб-серверов приложения
backend be-scalinglaravel
# Конфигурация здесь опущена

Что здесь происходит?

Создаётся правило acl letsencrypt-acl, которое ищет в пути запроса начало .well-known/acme-challenge/.

Если правило срабатывает, трафик перенаправляется в бэкенд letsencrypt-backend, который проксирует запросы на локальный сервер Certbot, запущенный на порту 8888.

Остальной трафик идёт к вашим приложениям.

Примените конфигурацию командой:

sudo service haproxy reload

Шаг 2: Получение сертификата (HTTP-валидация)


Теперь, когда HAProxy готов маршрутизировать запросы, мы можем получить наш первый сертификат. Обратите внимание на флаг --http-01-port.

sudo certbot certonly --standalone -d demo.scalinglaravel.com \
--non-interactive --agree-tos --email admin@example.com \
--http-01-port=8888

  • –standalone создаёт автономный веб-сервер Certbot.


  • –d demo.scalinglaravel.comдомен, для которого создаётся сертификат. Можно использовать несколько флагов –d для добавления нескольких доменных имён.


  • --non-interactive --agree-tos --email admin@example.com автоматизирует процесс, соглашаясь с условиями использования и указывая email для уведомлений


  • –http-01-port=8888 говорит Certbot работать на порту 8888. Запросы от Let's Encrypt будут приходить на стандартный порт 80, но HAProxy перенаправит их на этот порт.
Шаг 3: Подготовка сертификата для HAProxy


Let's Encrypt выдает два ключевых файла: сертификат (fullchain.pem) и приватный ключ (privkey.pem). HAProxy для работы требует один объединённый файл, где сначала идёт сертификат, а затем приватный ключ.

Создадим директорию и объединим файлы:

sudo mkdir -p /etc/ssl/demo.scalinglaravel.com

Объединяем файлы. ВАЖЕН ПОРЯДОК: сначала сертификат, потом ключ.

sudo cat /etc/letsencrypt/live/demo.scalinglaravel.com/fullchain.pem \
/etc/letsencrypt/live/demo.scalinglaravel.com/privkey.pem \
| sudo tee /etc/ssl/demo.scalinglaravel.com/demo.scalinglaravel.com.pem
Шаг 4: Настройка HTTPS в HAProxy


Теперь обновим наш фронтенд, чтобы он работал и на порту 443, используя новый сертификат.

frontend fe-scalinglaravel
bind *:80
bind *:443 ssl crt /etc/ssl/demo.scalinglaravel.com/demo.scalinglaravel.com.pem
# Подключаем наш файл
# Остальная часть конфигурации опущена
Шаг 5: Автоматическое продление


Чтобы настроить автоматическое продление, нужно:


  • получить новый сертификат;


  • создать файл сертификата для HAProxy.

По умолчанию Let’s en crypt создаёт задачу cron по пути /etc/cron.d/certbot

Он запускает её два раза в день и обновляет сертификат в том случае, если сертификат истёк.

Но мы не будем полагаться на стандартный cron от Certbot, а создадим свой скрипт: /opt/update-certs.sh

Ниже представлен сам файл:

# !/usr/bin/env bash
# Обновляем сертификат
certbot renew --force-renewal --tls-sni-01-port=8888
# Объединяйте новые файлы сертификатов с меньшими объёмами вывода (избегая использования tee и его вывода в стандартный вывод).
bash -c "cat /etc/letsencrypt/live/demo.scalinglaravel.com/fullchain.pem /etc/letsencrypt/live/demo.scalinglaravel.com/privkey.pem > /etc/ssl/demo.scalinglaravel.com/demo.scalinglaravel.com.pem"
# Безопасная перезагрузка HAProxy (не прерывает текущие соединения)
service haproxy reload

Все шаги, аналогичные предыдущим, кроме того, что используется --force-renewal и продление осуществляется каждый месяц

Если вы хотите использовать только HTTPS, то вы можете это сделать, оставив возможность обновлять сертификат. Пример конфигурации ниже:

frontend fe-scalinglaravel
bind *:80
bind *:443 ssl crt /etc/ssl/demo.scalinglaravel.com/demo.scalinglaravel.com.pem
# Перенаправление, если HTTPS не используется
redirect scheme https code 301 if !{ ssl_fc }
acl letsencrypt-acl path_beg /.well-known/acme-challenge/
use_backend letsencrypt-backend if letsencrypt-acl
default_backend be-scalinglaravel
Заключение


Мы реализовали отказоустойчивую и полностью автоматизированную систему управления SSL-сертификатами для HAProxy.

В итоге Let's Encrypt стучится на порт 80/443. HAProxy ловит запрос по ACL и направляет его на Certbot. Certbot подтверждает домен и выдаёт сертификат.

Мы создали PEM-файл, понятный HAProxy. Cron дважды в день запускает скрипт, который проверяет необходимость обновления, пересоздаёт PEM-файл и мягко перезагружает HAProxy. Теперь ваши сервисы за HAProxy всегда защищены актуальными SSL-сертификатами, а вы свободны от рутинных операций по их поддержке.
 
Сверху Снизу