Управление SSL-сертификатами: от хаоса на сотнях серверов к централизованному решению

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Что может стоять за словами “крупнейшая онлайн-школа Европы”? С одной стороны, это 1 тысяча уроков в час, 10 тысяч преподавателей, 100 тысяч учащихся. А для меня, инженера инфраструктуры, это еще и 200+ серверов, сотни сервисов (микро- и не очень), доменные имена от 2-го до 6-го уровня. Везде нужен SSL и, соответственно, сертификат к нему.



По большей части мы используем сертификаты Let’s Encrypt. Их преимущества в том, что они бесплатные, а получение полностью автоматизировано. С другой стороны, у них есть особенность: короткий — всего три месяца — срок действия. Соответственно, их приходится часто обновлять. Мы пытались это как-то автоматизировать, но всё равно оставалась масса ручной работы, и постоянно что-то ломалось. Год назад мы придумали простой и надёжный метод обновления этой кипы сертификатов и с тех пор забыли о такой проблеме.

От одного сертификата на одном сервере к сотням в нескольких дата-центрах


Когда-то давным-давно был всего один сервер. И на нём жил certbot, который работал из-под крона. Потом один сервер перестал справляться с нагрузкой, так что появился ещё один сервер. А потом ещё и ещё. На каждом из них были свои сертификаты со своим уникальным набором имён, и везде надо было настроить их обновление. Где-то при расширении копировали существующие сертификаты, а про обновление забывали.

Чтобы получить сертификат Let’s Encrypt, нужно подтвердить владение доменным именем, указанным в сертификате. Обычно это делается обратным HTTP запросом.


Вот пара стандартных трудностей, с которыми мы столкнулись по мере роста:

  • Не все новые сервера были доступны снаружи: некоторые убраны за балансировщик входящего трафика и не доступны более из интернета. На них сертификаты приходилось копировать вручную.
  • Также появились сервера вообще без HTTP. Скажем, с почтой. Или с базами данных. Или с каким-нибудь LDAP. Или ещё с чем-нибудь странным. Туда также приходилось копировать сертификаты вручную.

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



Беда в том, что в BrowserStack, которым пользуются тестировщики, невозможно добавить сертификат в список доверенных как минимум для iPad, Mac, iPhone. Так что тестировщикам приходилось мириться с постоянно выскакивающими предупреждениями об опасных сайтах.

Поиски решения


Конечно же прежде всего надо сделать мониторинг, чтобы узнавать о заканчивающихся сертификатах не тогда, когда они уже закончились, а немного раньше. Ну, хорошо. Мониторинг есть, мы теперь знаем, что скоро закончатся сертификаты там и тут. И что теперь делать?


Большое Ухо — старый бот, который сертификат не испортит.

А давайте использовать wildcard сертификаты? Давайте! Let’s Encrypt их уже выдаёт. Правда, придётся настроить подтверждение владения доменом через DNS. А DNS у нас живёт в AWS Route53. И придётся разложить реквизиты доступа в AWS по всем серверам. А при появлении новых серверов копировать всё это хозяйство туда тоже.

Хорошо, имена 3-го уровня покрываются wildcard-ом. А что делать с именами 4-го уровня и выше? У нас много команд, которые занимаются разработкой различных сервисов. Сейчас принято делить фронтенд и бэкенд. И если фронтенд получает имя 3-го уровня вроде service.skyeng.ru, то бэкенду норовят дать имя api.service.skyeng.ru. Хм, может быть запретить им впредь так делать? Отличная идея! А что делать с десятками уже существующих? Может быть железной рукой согнать их все на одно доменное имя? Заменим все эти имена различных уровней на URL-ы типа skyeng.ru/service. Технически это вариант, но сколько времени это займёт? И как для бизнеса обосновать необходимость таких действий? У нас 30+ команд разработки, каждую пойди уговори — это займёт как минимум полгода. А ещё мы создаём единую точку отказа. Как ни крути, это спорное решение.

Какие ещё есть идеи?.. Может быть сделать один сертификат, куда включим всё-всё-всё? И будем его устанавливать на все сервера. Это могло бы быть решением наших проблем, но Let’s Encrypt позволяет иметь только 100 имён в сертификате, а у нас различных микросервисов уже больше.

А что делать с тестировщиками? Так и не придумали ничего, а они постоянно жалуются. Всё фигня кроме пчёл. Пчёлы тоже фигня, но их много. Каждому разработчику или тестировщику выдаётся тестовый сервер — мы их называем тестингами. Тестинги не пчёлы, но их уже далеко за сотню. И на каждый деплоятся все проекты. Вообще все. И если для прода нужно N сертификатов, то здесь столько же на каждый тестинг. Пока что они самоподписанные. Было бы здорово заменить их на настоящие…

Два плейбука и один источник правды


Лебедь, рак и щука телегу никуда не привезут. Нужен единый центр управления полётами серверами. В нашем случае это Ansible. Certbot на каждом сервере — это зло. Пусть все сертификаты хранятся в одном месте. Если где-то кому-то нужен сертификат, то приходите в это место и берите с полки свежую версию. А мы позаботимся о том, чтобы в этом хранилище сертификаты были всегда актуальные.

Реквизиты доступа в AWS также присутствуют только в этом одном месте. Соответственно, у нас исчезают вопросы вроде настроить ещё и AWS CLI на новом сервере, кто имеет доступ в Route53 и тому подобное.

Все требуемые сертификаты описываются в одном файле в Ансибле в формате YAML:

    certificates:
      - common_name: skyeng.ru
        alt_names:
          - *.skyeng.ru
      - common_name: olympiad.skyeng.ru
        alt_names:
          - *.olympiad.skyeng.ru
          - api.content.olympiad.skyeng.ru
          - games.skyeng.ru
      - common_name: skyeng.tech
        alt_names:
          - *.skyeng.tech

      .  .  .

Периодически запускается один плейбук, который проходит по этому списку и делает свою тяжёлую работу — в сущности всё то же самое, что делает certbot:

  • создаёт аккаунт в Let’s Encrypt Certificate Authority
  • генерирует приватный ключ
  • генерирует (не подписанный ещё) сертификат — так называемый certificate signing request
  • отправляет запрос на подписание
  • получает DNS challenge
  • помещает полученные записи в DNS
  • отправляет запрос на подписание ещё раз
  • и, получив наконец подписанный сертификат, помещает его в хранилище.

Плейбук выполняется раз в сутки. Если он не смог обновить какие-то сертификаты по какой-либо причине — будь то сетевые проблемы или какие-то ошибки на стороне Let’s Encrypt — это не проблема. Обновится в следующий раз.

Теперь, когда на каком-нибудь хосте service нужен SSL, можно прийти в это хранилище и взять оттуда несколько файлов — простейшая операция, которую выполняет второй плейбук… Какие сертификаты нужны на данном хосте, описывается в параметрах этого хоста, в inventories/host_vars/server.yml:

    certificates:
      - common_name: skyeng.ru
        handler: reload nginx
      - common_name: crm.skyeng.ru

      .  .  .

Если файлы изменились, то Ансибл дёргает хук — типично это перезагрузить Nginx (в нашем случае это действие по умолчанию). И точно так же можно получать сертификаты от других CA, работающих по протоколу ACME.

Итого


  • У нас было множество разных конфигураций. Постоянно что-то ломалось. Частенько приходилось лазить по серверам и разбираться, что там опять отвалилось.
  • Теперь у нас два плейбука и всё записано в одном месте. Всё работает как часы. Жизнь стала скучнее.

Тестинги


Да, а что же тестировщики с их тестингами? Каждому разработчику или тестировщику выдаётся личный тестовый сервер — тестинг. Их в настоящее время около 200. Они имеют имена вида test-y123.skyeng.link, где 123 — это номер тестинга. Создание и удаление тестинга автоматизировано. Одно из составляющих действий — это установка на него SSL-сертификата. SSL-сертификат генерируется заранее, с именами по шаблону:

    ssl_cert_pattern:
      - *
      - *.auth
      - *.bill

      .  .  .

Всего около 30 имён. Так что в готовый сертификат входят имена

    test-y123.skyeng.link
    *.test-y123.skyeng.link
    *.auth.test-y123.skyeng.link
    *.bill.test-y123.skyeng.link

и так далее.

После увольнения разработчика или тестировщика его тестинг удаляется. Сертификат остаётся, готовый к использованию. Хранится это всё сами знаете где и раскладывается на хосты сами знаете как.

P.S.


Ещё по этой теме может быть интересно почитать, как Stack Overflow переходил на HTTPS:

  • Сотни доменов разного уровня
  • Websockets
  • Множество HTTP API (вопросы с прокси)
  • Всё сделать и не уронить производительность

Если остались вопросы, пишите в комментариях, буду рад ответить.
Источник: https://habr.com/ru/company/skyeng/blog/497432/


Интересные статьи

Интересные статьи

Операционными системами, которые основаны на Linux и Unix и работают в текстовом режиме, очень легко управлять. Учитывая то, как работает подсистема ввода-вывода Unix, программам, ожидающ...
Всем привет! Меня зовут Паша Лесюк, я работаю мобильным тестировщиком в компании Циан. В этой статье я расскажу о возможностях управления яблочными симуляторами из командной строки. ...
Всем привет. Когда я искал информацию о журналировании (аудите событий) в Bitrix, на Хабре не было ни чего, в остальном рунете кое что было, но кто же там найдёт? Для пополнения базы знаний...
Мы продолжаем публиковать доклады, прозвучавшие на RAIF 2019 (Russian Artificial Intelligence Forum). На этот раз своим опытом делится Вадим Аббакумов, кандидат физико-математических наук, гл...
Эта статья посвящена одному из способов сделать в 1с-Битрикс форму в всплывающем окне. Достоинства метода: - можно использовать любые формы 1с-Битрикс, которые выводятся компонентом. Например, добавле...