xacme: автоматические сертификаты
Система жизнеобеспечения HTTPS: клиент ACME (RFC 8555) упаковывает счёт, заказ, вызов dns-01 и получение сертификата в один вызов функции — а дисковое хранилище даёт продление по остатку срока.
Обзор
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 Выпуск и продление
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 возвращает истину для почти истёкшего сертификата.
Настоящий домен + LE staging: один выпуск dns-01 с записью на диск.
Таймер гл. 41 проверяет ежедневно; ниже 30 дней — IssueStored плюс горячая замена (дрель гл. 47 без разрывов).
Итоги
| Пункт | Вывод |
|---|---|
| Поток | directory→счёт→заказ→dns-01→finalize→загрузка, свёрнуто в одну функцию |
| DNS | интерфейс-структура, встроен Aliyun, зонд TXT прилагается |
| Продление | IssueStored решает по остатку дней; атомарная запись |
| Хранилище | переиспользование ключа счёта + происхождение цепочки |
| Дисциплина | staging для отладки; ключи на диске; секреты вне исходников |
- xrt · x509 — разбор срока и цепочки доверия