Спецификация: RFC 7030
Через EST клиент запрашивает сертификат X.509 по HTTPS. Versola использует его для одной цели: клиент, зарегистрированный с tls_client_auth и estEnrollment, сам получает и продлевает клиентский сертификат, которым аутентифицируется на /token (RFC 8705), с ключом, который создал сам. auth обслуживает эндпоинты и не хранит учетных данных УЦ; central решает, что выпускать, и поручает подписать УЦ, стоящему за client-certificates. Пошаговая инструкция — Автоматическое продление клиентского сертификата (EST), идея описана в Клиентские сертификаты и их продление, а API — это est.yaml в справочнике OpenAPI.
Статус
Реализован частично. Отмечено пунктов: 16 из 20. Маршруты отвечают 404, пока блок est у auth их не включит (справочник конфигурации).
Эндпоинты
-
GET /.well-known/est/cacerts(§4.1) — УЦ клиентов в виде PKCS#7 только с сертификатами, учетные данные не нужны -
GET /.well-known/est/csrattrs(§4.5) — отвечает204: запрос просят не нести атрибутов -
POST /.well-known/est/simpleenroll(§4.2.1) — первый сертификат, для клиента, у которого его нет -
POST /.well-known/est/simplereenroll(§4.2.2) — новый сертификат взамен того, что есть у клиента - Запрос
application/pkcs10, base64 от DER; ответapplication/pkcs7-mime; smime-type=certs-onlyсContent-Transfer-Encoding: base64 - Subject и альтернативные имена запроса на продление должны совпадать с теми, что у продлеваемого сертификата (§4.2.2); запрос с другим subject отклоняется с
400и причиной
Аутентификация
-
simpleenrollпо HTTP Basic: client id как имя пользователя и одноразовый токен выдачи как пароль (§3.2.3) -
simplereenrollпо текущему сертификату клиента в TLS handshake (§3.3.2), проверяется поmutual-tls.trusted-certificates; сертификат в заголовке запроса никогда не читается - Токен выдачи одноразовый, истекает (по умолчанию 24 часа, не больше 168), хранится только как хеш и показывается один раз. Неизвестный, использованный, истекший или чужой токен дает один и тот же
401 - Тело запроса не больше 16 КиБ
Что решает Versola
- В сертификате стоит subject, по которому клиент зарегистрирован (
mtlsAuthилиCN=<client>,OU=<tenant>,O=Versola, если он не задан), а не тот, что назван в запросе - Ключи: EC P-256 или RSA не короче 2048 бит
- Каждое продление требует нового ключа; запрос, который повторно использует ключ заменяемого сертификата, отклоняется с
400 - Сертификат продлевается только в последней трети срока жизни (
client-identity.renew-window); раньше будет403с указанием, когда окно откроется - Продления образуют цепочку, которая заканчивается на
client-identity.max-age; конец цепочки есть в каждом ответе в заголовкеVersola-Chain-Ends-At - Повторная выдача или
POST /configuration/clients/est/revokeлишают права продлевать все прежние сертификаты (401)
Отличия от RFC
- Два origin.
simpleenrollобслуживается на origin issuer’а, аsimplereenrollтолько на origin mutual-TLS (на другом404), поэтому клиенту нужны два базовых URL, чего §3.2.2 не предполагает. Стандартный EST-клиент с одним базовым URL получит404наsimplereenrollна origin issuer’а и ошибку TLS handshake наsimpleenrollна origin mutual-TLS; запускайте его отдельно для каждого origin. - Новый ключ при каждом продлении. §4.2.2 допускает тот же ключ (renew) наравне с новым (rekey); Versola тот же ключ отклоняет. Клиент, чей HSM не умеет создавать новый ключ для каждого сертификата, этим профилем пользоваться не может.
- Bearer-токены. Кроме Basic, токен выдачи можно отправить как
Authorization: Bearer. Это расширение: §3.2.3 называет Basic и Digest, аWWW-Authenticateобъявляет только Basic. cacertsиcsrattrsна обоих listener’ах. На основном listener’е они не требуют учетных данных, и именно там их забирает клиент без сертификата. На mutual-TLS listener’е они тоже обслуживаются, но его handshake требует клиентский сертификат, поэтому там они доступны только с действительным.- Расширения Versola в ответах.
429сRetry-Afterпри более чем 30 попыткахsimpleenrollв минуту на client id и реплику, заголовокVersola-Chain-Ends-Atи403«слишком рано» для продления до открытия окна. - Channel binding. §3.5 требует, чтобы сервер проверял значение
tls-unique, которое включает клиент, аtls-uniqueне определен для TLS 1.3, поэтому запрос сchallengePasswordотклоняется с400. - Не объявляется в
mtls_endpoint_aliases. Документ метаданных не перечисляет эндпоинты EST; клиент настраивается с обоими базовыми URL.
Не реализовано
- Channel binding (§3.5,
tls-unique): запрос с атрибутомchallengePasswordотклоняется - Полный CMC (§4.3,
fullcmc) - Произвольные метки (
/.well-known/est/<label>/...): один УЦ, без иерархии;csrattrsвсегда204 - Генерация ключа на стороне сервера (§4.4,
serverkeygen): ключ всегда клиентский
Куда смотреть
Клиентские сертификаты и их продление объясняет цепочку, поколения и отзыв. RFC 8705 описывает, для чего используется сертификат.