[Из песочницы] На пути к автоматизации выпуска SSL

Достаточно часто нам приходится работать с SSL сертификатами. Давайте вспомним процесс создания и установки сертификата (в общем случае для большинства).


  • Найти провайдера (сайт на котором мы можем купить SSL).
  • Сгенерировать CSR.
  • Отправить его провайдеру.
  • Отправить его провайдеру.
  • Подтвердить владение доменом.
  • Подтвердить владение доменом.
  • Получить сертификат.
  • Преобразовать сертификат в нужную форму (опционально). Например, из pem в PKCS #12.
  • Установить сертификат на веб сервер.

Относительно быстро, не сложно и понятно. Этот вариант вполне годится, если у нас есть максимум десяток проектов. А если их больше, и у них минимум по три окружения? Классический dev — staging — production. В этом случае стоит задуматься об автоматизации этого процесса. Предлагаю, немного углубиться в проблему и найти решение которое в дальнейшем минимизирует временные затраты на создание и обслуживание сертификатов. В статье будет присутствовать анализ проблемы и небольшое руководство к повторению.

Заранее оговорюсь: основная специализация нашей компании — .net, а соответственно IIS и прочие виндовые вытекающие. Поэтому, ACME клиент и все действия для него тоже будут описаны с точки зрения использования windows.


Для кого это актуально и некоторые исходные данные

Компания К в лице автора. URL (для примера): company.tld

Проект X — один из наших проектов, занимаясь которым я пришел к выводу что все таки нужно двигаться в сторону максимальной экономии времени при работе с сертификатами. У этого проекта есть четыре окружения: dev, test, staging и production. Dev и test находятся на нашей стороне, staging и production на клиентской.

Особенностью проекта является то, что у него есть большое количество модулей, которые доступны как поддомены.

То-есть, имеем следующую картину:

Для production используется купленный wildcard сертификат, тут вопросов не возникает. Но он покрывает только первый уровень поддомена. Соответственно, если есть сертификат для *.projectX.tld — то для staging.projectX.tld он работать будет, а вот для module1.staging.projectX.tld уже нет. А покупать отдельный как-то не хочется.

И это только на примере одного проекта одной компании. А проект, естественно, не один.

Общие для всех причины заняться решением этого вопроса выглядят примерно так:


  • Относительно недавно Google предложили уменьшить максимальный срок действия SSL сертификатов. Со всеми вытекающими.
  • Облегчить процесс выпуска и обслуживания SSL для внутренних нужд проектов и компании в целом.
  • Централизованное хранение записей о сертификатах, которое частично решает проблему подтверждения домена с помощью DNS и последующего автоматического обновления, а также решает вопрос доверия клиента. Все же, больше доверия вызывает CNAME на сервер компании партнера/исполнителя, чем на сторонний ресурс.
  • Ну, и наконец, в этом случае фраза «лучше иметь чем не иметь» подходит отлично.


Выбор провайдера SSL и подготовительные шаги

Из доступных вариантов бесплатных SSL сертификатов рассматривались cloudflare и letsencrypt. DNS для этого (и некоторых других проектов) как располагается на cloudflare, но я не сторонник использования их сертификатов. Поэтому, было решено использовать letsencrypt.
Для создания wildcard SSL сертификата нужно подтвердить владение доменом. Эта процедура предполагает создание некоторой DNS записи (TXT или CNAME), с последующей ее проверкой при выпуске сертификата. В Linux есть утилита — certbot, которая позволяет частично (или полностью для некоторых DNS провайдеров) автоматизировать этот процесс. Для Windows же из найденных и проверенных вариантов ACME клиентов я остановился на WinACME.

А запись для домена создана, переходим к созданию сертификата:

image

Нас интересует последний вывод, а именно — доступные варианты подтверждения владения доменом для выпуска wildcard сертификата:


  1. Создание DNS записей вручную (автоматическое обновление не поддерживается)
  2. Создание DNS записей с помощью acme-dns сервера (подробнее можно почитать тут.
  3. Создание DNS записей с помощью собственного скрипта (аналог плагина cloudflare для certbot).

На первый взгляд, третий пункт вполне подходит, но если DNS провайдер не поддерживает этот функционал? А нам необходим общий случай. А общий случай — это CNAME записи, уж их то все поддерживают. Следовательно, останавливаемся на пункте 2, и идем настраивать свой ACME-DNS сервер.


Настройка ACME-DNS сервера и процесс выпуска сертификата

Для примера, я создал домен 2nd.pp.ua, и в дальнейшем буду использовать его.

Обязательным требованием для корректной работы сервера является создание NS и А записи для его домена. И первый неприятный момент с которым я столкнулся — cloudflare (по крайней мере в режиме бесплатного использования) не позволяет одновременно создать NS и A запись для одного и того же хоста. Не то чтобы это было проблемой, но в bind это можно. Саппорт ответил, что их панель так делать не позволяет. Не беда, создадим две записи:

acmens.2nd.pp.ua. IN A 35.237.128.147
acme.2nd.pp.ua. IN NS acmens.2nd.pp.ua.

На данном этапе у нас должен резолвиться хост acmens.2nd.pp.ua.

$ ping acmens.2nd.pp.ua
PING acmens.2nd.pp.ua (35.237.128.147) 56(84) bytes of data

А вот acme.2nd.pp.ua резолвиться не будет, так как DNS сервер который его обслуживает еще не запущен.

Записи созданы, переходим к настройке и запуску ACME-DNS сервера. Жить он у меня будет на ubuntu server в docker контейнере, но запустить его можно везде где есть golang. Windows тоже вполне подойдет, но я все же предпочитаю Linux сервер.

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

$ mkdir config
$ mkdir data
$ touch config/config.cfg

Воспользуемся vim вашим любимым текстовым редактором и вставим в config.cfg образец конфигурации.

Для успешной работы достаточно подправить секции general и api:

[general]
listen = "0.0.0.0:53"
protocol = "both"
domain = "acme.2nd.pp.ua"
nsname = "acmens.2nd.pp.ua" 
nsadmin = "admin.2nd.pp.ua" 
records = 
    "acme.2nd.pp.ua. A 35.237.128.147",
    "acme.2nd.pp.ua. NS acmens.2nd.pp.ua.",                                                                                                                                                                                                  ]
...
[api]
...
tls = "letsencrypt"
…

Также, по желанию, создадим docker-compose файл в основной директории сервиса:

version: '3.7'
services:
  acmedns:
    image: joohoi/acme-dns:latest
    ports:
      - "443:443"
      - "53:53"
      - "53:53/udp"
      - "80:80"
    volumes:
      - ./config:/etc/acme-dns:ro
      - ./data:/var/lib/acme-dns

Готово. Можно запускать.

$ docker-compose up -d

На данном этапе должен начать резолвиться хост acme.2nd.pp.ua, и появиться 404 на https://acme.2nd.pp.ua

$ ping acme.2nd.pp.ua
PING acme.2nd.pp.ua (35.237.128.147) 56(84) bytes of data.

$ curl https://acme.2nd.pp.ua
404 page not found

Если этого не появилось — docker logs -f в помощь, благо, логи вполне читабельные.

Можем приступать к созданию сертификата. Открываем powershell от имени администратора и запускаем winacme. Нас интересуют выборы:


  • M: Create new certificate (full options)
  • 2: Manual input
  • 2: [dns-01] Create verification records with acme-dns (https://github.com/joohoi/acme-dns)
  • На вопрос о ссылке на ACME-DNS сервер вводим в ответ URL созданного сервера (https). URL of the acme-dns server: https://acme.2nd.pp.ua

В отвер клиент выдает запись которую надо добавить в существующий DNS сервер (процедура единоразовая):

[INFO] Creating new acme-dns registration for domain 1nd.pp.ua

Domain:              1nd.pp.ua
Record:               _acme-challenge.1nd.pp.ua
Type:                   CNAME
Content:              c82a88a5-499f-464f-96e4-be7f606a3b47.acme.2nd.pp.ua.
Note:                   Some DNS control panels add the final dot automatically.
                           Only one is required.

image

Создаем необходимую запись, и убеждаемся что она создалась корректно:

image

$ dig CNAME _acme-challenge.1nd.pp.ua +short
c82a88a5-499f-464f-96e4-be7f606a3b47.acme.2nd.pp.ua.

Подтверждаем что мы создали нужную запись в winacme, и продолжаем процесс создания сертификата:

image

Как использовать certbot в качестве клиента описано тут.

На этом процесс создания сертификата закончен, можно устанавливать его на веб-сервер и использовать. Если при создании сертификата создать также и задание в планировщике, то в дальнейшем процесс обновления сертификата будет происходить автоматически.

© Habrahabr.ru