По этому руководству API-клиент (например, банк с интеграцией по FAPI 2.0) сам получает клиентский сертификат и продлевает его с ключом, который он создал. В конце клиент аутентифицируется на /token сертификатом, который выпустил central, продлевает его до истечения, а вы знаете, что делать, если его ключ скомпрометирован. Идея, правила цепочки и отличия от RFC описаны в Клиентские сертификаты и их продление и RFC 7030. Если вы выпускаете клиентские сертификаты в собственном УЦ, прочитайте Свой PKI и пропустите остальное.
Нужны auth с listener’ом mutual-tls, central с бэкендом УЦ (client-certificates) и тенант, у которого задан mtlsCertificateHeader (как для любого клиента tls_client_auth).
1. Включите EST в auth
EST выключен, пока его не включат. Добавьте блок в auth.conf:
est {
enabled = true
ca-certificates = "/app/mtls/client-ca.crt" # только УЦ клиентов
}
ca-certificates обязателен, и в нем должен быть только УЦ, выпускающий клиентские сертификаты, а не весь bundle mutual-tls.trusted-certificates, где может быть УЦ edge (справочник конфигурации). На сгенерированных таргетах задайте для versola-tools EST_ENABLED=true и, кроме local и Kubernetes (где chart сам монтирует только УЦ клиентов в /app/mtls/client-trust/ca.crt), EST_CA_CERTIFICATES=<путь в контейнере auth>; для Kubernetes см. PKI в Kubernetes. Маршруты такие:
| Где | Маршруты |
|---|---|
Публичное имя auth (issuer) | /.well-known/est/cacerts, csrattrs, simpleenroll |
| Публичное имя mutual-TLS listener’а | /.well-known/est/cacerts, csrattrs, simplereenroll |
Поэтому клиенту нужны два базовых URL: выдача на origin issuer’а, продление на origin mutual-TLS. Стандартный EST-клиент с одним базовым URL получит 404 на simplereenroll на origin issuer’а и ошибку TLS handshake на simpleenroll на origin mutual-TLS, поэтому запускайте его отдельно для каждого origin. cacerts и csrattrs на origin issuer’а не требуют учетных данных, и именно там их забирает клиент без сертификата; на origin mutual-TLS им нужен действительный клиентский сертификат.
2. Зарегистрируйте клиента
Зарегистрируйте клиента (веб или сервисного вида) с authMethod: tls_client_auth и estEnrollment: true. Сертификата у него пока нет. Subject его сертификата — это его mtlsAuth (например subject_dn) или, если он не задан, CN=<client>,OU=<tenant>,O=Versola. Subject никогда не берется из запроса клиента и не меняется при продлениях, поэтому регистрация остается прежней. estEnrollment нельзя сочетать с issueEdgeClientCertificate, enrollEdgeClientCertificate и сертификатом, который вы передаете сами. См. Клиент.
3. Создайте токен выдачи
curl -u central:<central secret> -X POST \
"https://central.example.com/configuration/clients/est/enrollment-tokens?clientId=bank-a&validityHours=48"
В ответе есть token, его expiresAt и subject, который должен назвать запрос. Токен показывается один раз; хранится только его хеш. По умолчанию он живет 24 часа (validityHours до 168) и срабатывает один раз. Новый токен заменяет неиспользованные прежние токены клиента. Передайте токен и subject оператору клиента по защищенному каналу.
4. Клиент проходит выдачу
Клиент создает собственный ключ, формирует PKCS#10 ровно для того subject, который ему передали, и отправляет его на simpleenroll, передавая client id и токен как HTTP Basic (или токен как Bearer). OpenSSL перечисляет subject от самой общей части к самой частной, наоборот относительно строки RFC 4514, которую вам дали:
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
-keyout bank-a.key -subj "/O=Versola/OU=acme/CN=bank-a" -outform DER | base64 > request.b64
curl -sS -u "bank-a:<enrolment token>" \
-H "Content-Type: application/pkcs10" --data-binary @request.b64 \
-D headers.txt https://id.example.com/.well-known/est/simpleenroll > response.b64
base64 -d response.b64 | openssl pkcs7 -inform DER -print_certs -out chain.pem
Принимаются ключи EC P-256 или RSA не короче 2048 бит. В ответе certs-only PKCS#7 с цепочкой и без ключа; свой сертификат выберите по subject. Запрос, отклоненный с 400, токен не расходует. simpleenroll ограничен 30 попытками в минуту на client id и реплику (429, Retry-After). УЦ, которому доверять, берите из /.well-known/est/cacerts.
5. Клиент продлевает сертификат
Сертификат живет client-certificates.validity (по умолчанию 14 дней) и продлевается только в своей последней трети (client-identity.renew-window); раньше simplereenroll отвечает 403 и сообщает, когда окно откроется. Клиент отправляет новый PKCS#10 с новым ключом на origin mutual-TLS, предъявляя текущий сертификат:
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
-keyout bank-a.next.key -subj "/O=Versola/OU=acme/CN=bank-a" -outform DER | base64 > request.b64
curl -sS --cert bank-a.crt --key bank-a.key \
-H "Content-Type: application/pkcs10" --data-binary @request.b64 \
https://id-mtls.example.com/.well-known/est/simplereenroll > response.b64
Subject и альтернативные имена должны быть теми же, что у продлеваемого сертификата, а ключ должен отличаться от прежнего: клиент, чей HSM не умеет создавать новый ключ для каждого сертификата, этим профилем пользоваться не может. Запрос с атрибутом challengePassword (channel binding, RFC 7030 §3.5) отклоняется с 400; отправляйте запрос без него. Истекший сертификат сам собой не продлевается: создайте новый токен и пройдите выдачу заново.
Токены не следуют за сертификатом. Токен, выпущенный, когда клиент предъявлял старый сертификат, несет его отпечаток (cnf.x5t#S256) и с продленным не работает. Клиент продолжает предъявлять старый сертификат со старыми токенами, пока они не истекут, а новый использует для новых токенов. Старый сертификат остается действительным, а сертификат по умолчанию продлевается в последней трети жизни, поэтому на перекрытие в эту треть можно рассчитывать. Спланируйте переход так, чтобы новый сертификат использовался начиная со следующего запроса токена (Токены с привязкой к отправителю). Клиент также должен перечитывать новый ключ в свой TLS-стек без перезапуска.
6. Цепочки, продление цепочки и отзыв
Продления образуют цепочку, начатую при выдаче. По достижении client-identity.max-age (по умолчанию год) central отказывает в продлении (403), пока вы не продлите цепочку:
curl -u central:<central secret> -X POST \
"https://central.example.com/configuration/clients/est/extend?clientId=bank-a"
При client-identity.auto-extend = true central делает это сам. Граница мягкая: сертификат, выпущенный незадолго до нее, живет весь свой срок, так что клиент может работать и после Versola-Chain-Ends-At, который есть в каждом ответе. GET /configuration/clients показывает est.pending, est.certificateExpiresAt и est.chainEndsAt.
Если ключ мог утечь:
curl -u central:<central secret> -X POST \
"https://central.example.com/configuration/clients/est/revoke?clientId=bank-a"
Отзывается право продлевать, а не сам сертификат: каждый выпущенный до сих пор сертификат относится к поколению цепочки, и ни один не может продлиться (401). Повторная выдача с новым токеном начинает новое поколение. Сами сертификаты продолжают аутентифицировать до истечения; чтобы отрезать и их, смените subject в mtlsAuth клиента или удалите клиента. Сертификат, который заменило продление и который снова приходит продлеваться после 3-минутной отсрочки, означает, что ключ у двоих: цепочка закрывается (403, est_chain_fork_detected), и вы выдаете клиенту сертификат заново. Клиент, который больше не зарегистрирован для EST (estEnrollment выключен), при продлении получает 401.
За чем следить
| Где | Что |
|---|---|
| Клиент | Дни до истечения, последнее продление, перечитывание сертификата после продления |
Метрика auth | est_requests_total{operation,outcome}: рост forbidden, unauthorized или chain_fork |
Метрика central | est_certificate_requests_total{operation,outcome} |
| Состояние клиента | est.certificateExpiresAt и est.chainEndsAt в GET /configuration/clients; настройте оповещение на клиента, чей сертификат в последней трети срока и не продлился |
См. Наблюдаемость. Отзыв — это истечение: Versola не читает CRL и OCSP, поэтому украденный сертификат ограничивает короткий срок жизни.
Свой PKI
Если вы не используете EST, выпустите новый сертификат в своем УЦ с тем же subject, по которому клиент зарегистрирован, передайте его клиенту и пусть он запросит новые токены. В Versola ничего не меняется. Смена subject или УЦ не входит в EST: что не охвачено.
Что дальше
- RFC 7030 — EST: что реализовано и чем Versola отличается.
- Вызов API с токеном, привязанным к сертификату
- Клиент