Глава 38 / 51
Том 5 · Расширения, эксплуатация и практика

xacme: автоматические сертификаты

Система жизнеобеспечения HTTPS: клиент ACME (RFC 8555) упаковывает счёт, заказ, вызов dns-01 и получение сертификата в один вызов функции — а дисковое хранилище даёт продление по остатку срока.

Обзор

Позиционирование: автоматическое продолжение гл. 12 (управление сертификатами) — ручной openssl сменяется API; стыкуется с сертификатным реестром гл. 42. Предусловие: вариант build.bat xacme. Живая проверка требует настоящего домена и контроля DNS.

38.1 Поток ACME

Цикл RFC 8555: регистрация счёта в directory ЦС (ключ ES256 + подписи JOSE) → заказ доменов (шаблоны допустимы) → прохождение вызова dns-01 (публикация выданной ЦС TXT-записи в DNS) → finalize с CSR → загрузка цепочки. xacmeClientInit создаёт клиента (разбирает directory, регистрирует или переиспользует счёт); xacmeClientIssue прогоняет весь цикл и возвращает цепочку PEM. Нейтральность к ЦС: пресеты LE / ZeroSSL / Google / Buypass — смена ЦС есть смена URL.

38.2 DNS-провайдеры

dns-01 требует права записи в DNS: интерфейс провайдера — чистая структура (id / Add / Remove / необязательный Propagate); встроен Aliyun (dns_ali, подпись V3); прочие вендоры подключаются заполнением структуры — без регистрации и глобального состояния. Библиотека несёт собственный зонд распространения TXT — UDP-запрос к авторитетному NS подтверждает видимость записи, прежде чем ЦС позовут проверять.

38.3 Выпуск и продление

Продление в один шаг (IssueStored)
xacmeclient* pClient;
xstrview tDomain = xrtStrView("example.com");
bool bRenewed;

pClient = ...;  /* xacmeClientInit(движок, PEM ЦС, URL directory, ключ счёта) */
char* sChain = xacmeClientIssueStored(pClient, &tDomain, 1,
    &tDnsProvider, sStoreRoot, 30, &bRenewed);
if ( sChain != NULL && bRenewed ) {
    install_cert(sChain);   /* горячая замена (отработано в гл. 47) */
}
xrtFree(sChain);

Семантика IssueStored: если остаток жизни локального сертификата не меньше порога в днях — вернуть существующую цепочку как есть (pbRenewed=false); иначе полный выпуск с записью на диск. Проверка остатка строится на разборе x509 (xrt), без внешних процессов.

38.4 Хранилище и восстановление

Хранилище — соглашение о каталогах: accounts/ держит ключи счетов (PKCS#8 PEM; Init переиспользует их, минуя повторную регистрацию), certs/<домен>/ — полную цепочку и происхождение ЦС, всё пишется атомарно (xrtFileWriteAtomic). Проверка продления, чтение сертификата и чтение цепочки ЦС — отдельные функции: свою политику продления можно собрать и без IssueStored.

38.5 Контракт

ВопросГлавное
Владениеклиент и цепочка из Issue выделяются библиотекой; Destroy / xrtFree освобождают
Сетьсвой синхронный HTTPS-транспорт (движок взаймы или свой); трафик сконцентрирован в окне выпуска
Секретыключи счёта и DNS — через хранилище/окружение (слои гл. 44), никогда в исходник
Ошибкипотоковая ошибка несёт стабильные коды домена "xrt.acme.flow" — классифицируемы для повторов

Частые ошибки

Продакшн-ЦС вместо полигона
Симптом
Частые перевыпуски бьют о рейт-лимиты Let's Encrypt — домен блокируется на часы.
Причина
Отлаживайтесь на пресете LE staging (без производственной квоты); порог продления IssueStored не должен означать «продлевать каждый раз».
Ключ счёта каждый раз новый
Симптом
После рестарта счёт не сходится — ЦС видит новую регистрацию, история заказов теряется.
Причина
Ключ счёта обязан сохраняться в хранилище и передаваться в Init для переиспользования — IssueStored это делает; в обход — сами себе хозяин.

Упражнения

БазаОфлайн-проверки

Прогнать directory staging + конфиг счёта + реестр провайдеров (Count/Id); NeedRenew возвращает истину для почти истёкшего сертификата.

Приёмка: в реестре есть "ali"; остаток дней сходится с openssl.
ПродвинутыйВыпуск на staging

Настоящий домен + LE staging: один выпуск dns-01 с записью на диск.

Приёмка: цепочка загружается в xrt TLS; повторный прогон даёт «срок не вышел — как есть».
ВызовРобот продления

Таймер гл. 41 проверяет ежедневно; ниже 30 дней — IssueStored плюс горячая замена (дрель гл. 47 без разрывов).

Приёмка: замена без единого разрыва; отказы дают классифицированную тревогу, а не тишину.

Итоги

ПунктВывод
Потокdirectory→счёт→заказ→dns-01→finalize→загрузка, свёрнуто в одну функцию
DNSинтерфейс-структура, встроен Aliyun, зонд TXT прилагается
ПродлениеIssueStored решает по остатку дней; атомарная запись
Хранилищепереиспользование ключа счёта + происхождение цепочки
Дисциплинаstaging для отладки; ключи на диске; секреты вне исходников
Дальнейшее чтение по xrt
  • xrt · x509 — разбор срока и цепочки доверия