
Оглавление
Вступительная часть
Привет, меня зовут Денис Трофимов, и я работаю DevOps инженером.
Никогда не считал себя разработчиком, но всегда любил что‑нибудь написать для себя или других.
Сегодня я бы хотел рассказать о небольшом проекте, который тянется как спагетти‑код немного, немало около двух лет.
Я назвал проект TLSS, что то вроде TLS Service, или быть может как‑то иначе, не так важно.
Не знаю, стоит ли сказать спасибо за идею моему коллеге или проклянуть, но однажды он вскользь упомянул, что перед развертыванием нового стенда стоит подумать о генерации сертификатов и выбрать, чем пользоваться. Тут‑то я и подумал, зачем мне скрипты, которыми можно все сгенерировать, если я могу написать приложуху?!
Поискав в интернете минут десять и не найдя ничего подходящего, как часто со мной бывает, я просто забил, и пошел писать свое.
Конечно, говоря про скрипты сейчас этот вопрос не стоит так остро (не то чтобы он когда‑либо стоял), любая нейросеть генерирует скрипт за считанные секунды, но тогда, в те прекрасные времена... Ну вы поняли.
Приступая к делу, я определил основной концепт всего приложения: оно должно быть «карманным», то есть работать где угодно, просто переноситься и сохранять информацию.
Как итог можно выделить основные особенности:
Все хранится в sqlite, почти (конфигурация генерируется отдельно).
Все ключи\пароли в базе зашифрованы.
Бэкапы и перенос данных не проблема - одно
кольцоместо хранения, что бы контролировать все данные как обычный файл со всеми вытекающими плюсами.Управляется через WEB UI.
Есть API для автоматизации процессов.
Насчет работы где угодно не уверен, собиралось и проверялось только на Linux\Mac.
Функционал
Корневые CA\Sub CA

В первый раз запустив приложение, вас встретит раздел Core CA — создания корневых сертификатов, логично, без них ничего работать не будет, или, если быть точным, выписать сертификаты не получится.
Корневой и промежуточный сертификат имеет ряд особенностей, которые стоит помнить, если вы выписываете сертификаты на сроки в пределах человеческой жизни.
Отзыв\пересоздание
Пересоздание корневого сертификата влечет за собой:
Пересоздание промежуточного сертификата.
Отзыв всех сертификатов, которые были подписаны промежуточным сертификатом.
Отзыв промежуточного сертификата.
Все отозванные ранее сертификаты удаляются.
Выписываются новые CA\Sub CA сертификаты.
Пересоздание промежуточного сертификата влечет за собой:
Отзыв всех сертификатов, которые были подписаны этим сертификатом.
Все отозванные ранее сертификаты удаляются.
Выписывается новый Sub CA сертификат.
Внешние CA

Если у вас по какой‑то причине уже имеется свой CA или цепочка из CA\Sub CA, сертификат\ключ, вы можете перейти в раздел External CA и создать сущность для вашего набора сертификатов для дальнейшей идентификации в подразделе Add CA entities, после чего в Add External CA закинуть ваши файлы.
Ключи, как при любой другой генерации, будут зашифрованы, а вы сможете выписывать новые сертификаты от имени этого CA\Sub CA.
Внешние CA используются независимо от внутренних CA приложения, проще говоря, они сами по себе, приложение за них не отвечает, не использует для генерации CRL, не пересоздает их и так далее
Серверные сертификаты

Самый часто используемый функционал, выписываем сертификаты с Extended Key Usage:
TLS Web Server Authentication
TLS Web Client Authentication
Изначально тут был только TLS Web Server Authentication, но я пока добавил оба признака, возможно, требуется добавить возможность выбора при генерации.
Поддерживается 3 алгоритма:
RSA
ECDSA
ED25519
Для генерации сертификатов вам потребуется создать сущность, которая бывает двух вариантов:
непривязанная сущность, раздел Add entities — просто некая абстрактная единица, на которую можно выписывать сертификаты.
внешний сервер, раздел Add servers — реально существующий сервер, для подключения к которому используется пароль или ssh‑ключ (создается в Add ssh key, о нем ниже). Требует указания пути хранения сертификата. После создания порт сервера всегда проверяется на доступность.
Add ssh key
В рамках подключения к удаленному серверу рассмотрим раздел Add ssh key, выполняющий роль хранилища ключей для подключения по ssh и имеющий следующий функционал:
При первичном запуске приложения — создается Default ключ.
При наличии уже существующих ключей просто загрузите их, если используете Passphrase передайте его в соответствующем поле.
Как итог TLSS может выступать в роли хранилища всех ваших SSH ключей.
App type
Пункт App type дает на выбор два варианта сохранения на удаленный сервер и разделены условно (требует дальнейшего развития и более логичного разделения):
haproxy — сохраняет сертификат как bundle
nginx — сохраняет как отдельные файлы.
Независимо от способа, рядом выгружаются CA.
Отзыв сертификата
При отзыве серверного сертификата и последующего роллбека сертификат не перезаписывает существующий, если такой был сгенерирован, то есть каждый сертификат уникален и существует автономно. Поведение при создании сертификата аналогично.
Клиентские сертификаты

Логически раздел задумывался для выпуска персонализированных сертификатов.
Сертификат выписывается с Extended Key Usage:
TLS Web Client Authentication
В отличии от серверных сертификатов в раздел добавлены пункты:
OID — создается в разделе Add OIDs и, возможно, вам потребуется для дополнительной идентификации вашего сертификата
Password — для создания запароленного контейнера pkcs12
OID
OID — Object IDentifier древовидный цифровой код, к примеру — 1.3.6.1.5.5.7.3.1, что расшифровывается как:
1 — ISO assigned
3 — ISO Identified Organization
6 — US Department of Defense
1 — Internet
5 — Security
5 — Mechanisms
7 — PKIX
3 — id‑kp, arc for extended key purpose OIDS
1 — id_kp_serverAuth
Расписывать подробно можно на целую статью, по этому оставлю только ссылку на wiki
Добавлю лишь, что для себя вы без каких‑либо проблем можете зарегистрировать свой OID через официальную страницу IANA, никаких проблем при указании отечественной почты не вызвало, ребята быстро взяли в работу и выдали в течение недели.
Password
Поле с Password как уже упоминалось, служит для генерации закрытого контейнера pkcs12 и без этого сертификат не создать.
Выгрузить сертификат можно 3-мя способами:
zip — архив
pkcs12 (PKCS12 Modern) — современная реализация (не работает на macOS и других древних ОС, Google упоминает в примерах win 7, java и так далее) встроенное хранилище ключей на macOS выдает ошибку и не принимает контейнер.
pkcs12-legacy (PKCS12 Legacy) — старая реализация (версия для macOS)
Отзыв сертификата
Работает аналогично серверным сертификатам.
EST
Добавлена поддержка протокола EST (RFC 7030)
Имя | Путь | Описание |
Distribution of CA | -/.well-known/est/cacerts/ | получение цепочки корневых CA |
Enrollment of Clients | /.well-known/est/simpleenroll | получить первичный сертификат |
Re-enrollment of Clients | /.well-known/est/simplereenroll | перевыпустить сертификат на основе сертификата полученного через simpleenroll |
CSR Attributes | /.well-known/est/csrattrs | получить список атрибутов для CSR запроса |
В конфигурационном файле используется пункт estCSRAttrs с параметром rfc9908 который принимает два значения:
true - использовать современную реализацию RFC 9908
false - использовать RFC 7030
Первичный пользователь для авторизации и получения сертификата создается в разделе Add EST users

Отмечу пару пунктов:
Max uses - определяет сколько раз данный пользователь может авторизоваться и получить сертификат.
TTL - определяет как долго живет учетная запись, даже если ей не успели воспользоваться.
Signing CA - указываем каким CA внутренним или внешним будет подписываться выдаваемый сертификат.
Как и с выдачей других сертификатов стоит помнить все что подписывается внешними CA не контролируется\не отзывается
Вы так же можете создать первичный сертификат в разделе Add EST certs и зашить его в ваше устройство

В пункте Revoke EST certs по аналогии с другими пунктами вы можете отозвать сертификаты подписанные внутренним CA
CRL
Информация о списке отзыва добавляется как url к каждому выпущенному сертификату и берется из конфигурационного файла.
Обновляется как через заданный интервал, так и через API запрос, больше сказать особо нечего.
Для внутренних контуров кажется логично было бы использовать ocsp протокол, но я посчитал его излишне замороченным, напротив CRL на мой взгляд являет собой более прозрачную и универсальную реализацию.
API

API построено на API ключах, генерируется в разделе API keys и пока принимает несколько значений:
write API
read API
admin — full access
В разделе API examples можно посмотреть доступные url и содержимое для отправки.

Tools

В разделе пока содержится только Certificate Info, следуя из названия, предоставляет возможность быстро проверить содержимое сертификата.
Overview

Раздел призван пользователям просматривать различную статистику. Находится в зачаточном состоянии, так как пока не придумал, что и как должно там отображаться.
Заключение
В заключении хотелось бы поблагодарить вас за уделенное время, буду благодарен за комментарии и предложения. Если кому то пригодится, будет совсем хорошо, засим откланиваюсь.
Ссылка на github тут.
Вышло обновление 1.4.0, что привнесло не мало исправлений:
Add:
Добавлена поддержка EST протокола RFC 7030
Fix:
Из-за того что я забыл добавить в конфигурацию ссылки на CDP для root ca\sub ca, а вместо них оставил ссылку на бандл, ваш текущий подписывающий сертификат будет без него, как следствие все выпущенные сертификаты при полной проверке например через openssl
openssl verify -crl_check_allвыдадут ошибку. К сожалению единственный путь, это перевыпустить sub ca после изменения в конфигурации.При создании нового Sub ca кеш не сбрасывался, что приводило к пересозданию сертификатов с подписью отозванного Sub ca
Не обновлялся CRL после пересоздания Sub ca (требовалось ждать, следующего обновления)
Обновления метки времени (next update) в crl
Update:
revoke\rollback сертификатов сразу обновляет CRL не дожидаясь глобального обновления.