Сертификат действует, а AD его не принимает: четыре проверки сильной привязки
Срок действия сертификата тут ни при чём: после обновлений контроллеров домена от 9 сентября 2025 года AD пускает только тех, у кого есть сильная привязка к учётной записи, а ключ реестра StrongCertificateBindingEnforcement больше не поддерживается. Ниже четыре проверки, которыми я за час нахожу, чего именно не хватает, и разбор на офисе из 19 рабочих мест.
Почему действующий сертификат отклоняется, если срок и цепочка в порядке
Классический звонок звучит так: «Сертификат выпущен в прошлом году, цепочка доверия зелёная, токен вставлен, а в домен не пускает». Администратор открывает сертификат, видит «Этот сертификат действителен», и дальше начинается самое неприятное: он идёт продлевать, перевыпускать корневой, чистить кэш. Я видел этот цикл у десятка клиентов. Всё мимо. Проверка срока и цепочки — это вопрос «можно ли доверять сертификату». Контроллер домена после обновлений задаёт второй вопрос: «а кто именно этот сертификат предъявил и можно ли это доказать однозначно». Если на второй вопрос ответа нет, срок действия роли не играет. Если у вас смарт-карты, 802.1X или любая другая вход-по-сертификату схема, а аудит Active Directory последний раз делали, когда Windows Server 2012 ещё считался свежим, начните с этой статьи.
Что поменялось по факту. По документации Microsoft (KB5014754), KDC теперь требует сильную привязку сертификата к учётной записи. Сильная привязка — это либо расширение с SID пользователя внутри самого сертификата (его добавляет Enterprise CA при выдаче по online-шаблонам), либо ручная запись в атрибуте altSecurityIdentities одного из трёх сильных типов. Переход шёл поэтапно с 10 мая 2022 года; 11 февраля 2025 года контроллеры без ключа реестра перешли в режим полного принуждения, а 9 сентября 2025 года возможность вернуться в режим совместимости закончилась, и StrongCertificateBindingEnforcement больше не поддерживается. Вывод простой: отката нет, есть только проверка и исправление.
Эта статья про диагностику одного конкретного сертификата, а не про стратегию миграции парка. Общую картину — хронологию, разбор шаблонов, план работ по волнам — я уже разложил в материале про событие Kdcsvc 39 и сильное сопоставление, туда и идите, если вам нужен план на весь парк. Здесь другое: у вас сломался вход у конкретного человека, и надо за час понять, какой из четырёх возможных дефектов у него. Я вывел для себя порядок из четырёх проверок и не отступаю от него годами, потому что каждая следующая имеет смысл, только если предыдущая пройдена.
Проверка 1. Какое событие пишет KDC и на каком контроллере
Начинать надо не с реестра и не с сертификата, а с журнала. KDC пишет события в журнал System, источник Kdcsvc. По документации Microsoft: событие 39 означает, что сильная привязка не найдена и нет корректного SID-расширения (в режиме совместимости это предупреждение, в режиме принуждения — ошибка); событие 40 говорит, что сертификат выпущен раньше, чем создана учётная запись (оно пишется только в режиме совместимости); событие 41 — SID в сертификате не совпадает с SID пользователя. Для Windows Server 2008 R2 SP1 и 2008 SP2 номера другие (41, 48 и 49 соответственно), поэтому в смешанной среде сверяйте не только номер, но и текст сообщения. Если у вас ещё живёт такой сервер, у вас проблемы поважнее сертификатов.
В домене почти всегда больше одного контроллера, а аутентификацию обслуживает тот, до которого дошёл запрос. Поэтому смотреть журнал на одном DC и радоваться отсутствию событий — классическая ошибка: событие лежит на соседнем. Я собираю данные со всех контроллеров одним проходом. Удалённое чтение журнала через параметр ComputerName не требует PowerShell remoting, но требует, чтобы на DC был открыт доступ к службе журналов событий в брандмауэре — это прямо написано в документации по Get-WinEvent. И ещё одна мелочь, на которой спотыкаются: в KB источник событий назван Kdcsvc, а в «Просмотре событий» на живом контроллере он может отображаться как Kerberos-Key-Distribution-Center. Поэтому я не вписываю имя провайдера в фильтр жёстко, а отбираю события по номерам и затем отсекаю чужие по совпадению имени — так скрипт ничего не теряет из-за разницы в названии.
$dcs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
foreach ($dc in $dcs) {
Get-WinEvent -ComputerName $dc -FilterHashtable @{
LogName='System'; Id=39,40,41; StartTime=(Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue |
Where-Object { $_.ProviderName -match 'Kdc|Kerberos-Key-Distribution' } |
Select-Object @{n='DC';e={$dc}}, TimeCreated, Id, LevelDisplayName, Message
}Как читать результат. Одни тридцать девятые — у пользователя нет ни SID в сертификате, ни ручной привязки, идите к проверкам 3 и 4. Событие 41 — привязка есть, но она чужая: сертификат выдан одному аккаунту, а предъявлен от имени другого, или учётную запись пересоздали с тем же именем, а SID у неё уже другой. Событие 40 в наши дни встречается редко, потому что оно живёт только в режиме совместимости, а возвращаться в него нельзя. Если же в журнале пусто, а вход не работает, значит, отказ приходит не от KDC: возможно, аутентификацию делает Schannel (LDAPS, веб-службы, часть сценариев 802.1X), и там свои правила — о них в разделе про реестр.
Проверка 2. Реестр: почему StrongCertificateBindingEnforcement больше ничего не лечит
Это самый болезненный раздел, потому что именно сюда тянет руку у каждого, кто гуглил проблему три года назад. Старая инструкция выглядит убедительно: в ветке HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc создаём параметр StrongCertificateBindingEnforcement типа REG_DWORD, ставим значение 1 (режим совместимости), перезагрузка не нужна, всё работает. Так и было. Согласно KB5014754, значение 1 — совместимость, 2 — принуждение, 0 — отключение проверки, которое Microsoft не рекомендует. А потом пришёл сентябрь 2025 года, и поддержка этого ключа закончилась. Значение в реестре можно оставить, можно переписать, можно перерисовать на листочке — контроллер на него больше не ориентируется. Я до сих пор нахожу у клиентов эти ключи, аккуратно созданные в 2022 году и честно ничего не делающие. Это самый дорогой по времени «обход» из всех, что я знаю: он занимает полдня, а пользы не приносит.
Тем не менее реестр проверить стоит, но ради одного: убедиться, что вы не потеряли два часа на лечение следствием. Команда ничего не меняет, только читает.
reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcementЕсли параметр найден, зафиксируйте значение и не трогайте его: на поведение оно не влияет, а убрать его можно позже, при плановой чистке. Если параметра нет, это нормально — на многих контроллерах его никогда и не создавали. Отдельная история — Schannel. В документации Microsoft сказано, что значение по умолчанию параметра CertificateMappingMethods изменилось с 0x1F на 0x18, то есть слабые методы сопоставления (по субъекту и издателю, по издателю, по UPN) по умолчанию отключены. Совет «поставьте 0x1F и проверьте» в KB есть, но только как диагностика, с прямым предупреждением, что так вы вернётесь к слабым методам. В продуктив я такое не оставляю никогда: открытая дверь, повешенная на костыль, — это не решение. Если после вашего эксперимента вход заработал, вы узнали причину (слабое сопоставление), а чинить всё равно придётся привязку.
Если не хочется тратить на это день, мы в АйТи-Фреш можем разобрать журналы и реестр ваших контроллеров за пару часов и сразу сказать, что из этого безвредный мусор, а что действительно держит вход.
Проверка 3. Есть ли SID-расширение внутри самого сертификата
Если реестр оказался красной селёдкой, то первым подозреваемым становится сам сертификат. Предпочтительная сильная привязка — расширение с OID 1.3.6.1.4.1.311.25.2: это некритическое расширение, которое Enterprise CA добавляет в сертификаты, выданные по online-шаблонам. Достаточно посмотреть, есть ли оно. Экспортируйте сертификат пользователя в файл .cer (закрытый ключ для этого не нужен) и выгрузите его содержимое штатной утилитой certutil: команда dump с именем файла выводит все поля и расширения.
certutil -dump C:\temp\user.cerВ выводе ищите блок расширений и в нём OID 1.3.6.1.4.1.311.25.2. Если читать простыню certutil лень, можно проверить то же самое одной строкой через .NET. Пустой вывод означает, что расширения нет.
$c = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 'C:\temp\user.cer'
$c.Extensions | Where-Object { $_.Oid.Value -eq '1.3.6.1.4.1.311.25.2' }Если расширения нет, причин три, и они разные по цене. Первая и самая безобидная: сертификат выпущен до обновления центра сертификации. Документация прямо говорит, что обновление CA не требует продления, но сертификат с SID вы получите только новый — старый расширением не обрастёт. Вторая: шаблон настроен так, что центр сертификации расширение не добавляет. В KB описан механизм: установка бита 0x00080000 в атрибуте msPKI-Enrollment-Flag шаблона командой certutil -dstemplate; Microsoft прямо предупреждает, что этим снимается защита. Такой флаг мог поставить предыдущий подрядчик «чтобы заработало в 2022-м», и он тихо дожил до сегодняшнего дня. Проверьте шаблон: прочитать настройки можно той же утилитой certutil с ключом dsTemplate. Третья причина: сертификат выдал не Enterprise CA от Microsoft. В KB сказано, что в окружениях со сторонними центрами сертификации новое расширение не появится само, и нужно либо договариваться с вендором центра, либо идти на ручные привязки.
Если расширение есть, проверьте, что оно относится к тому человеку. Это ловушка события 41: SID в сертификате есть, но принадлежит другой учётной записи (пользователя пересоздали, перенесли между доменами или выдали сертификат на «похожего» сотрудника). Сравните SID из расширения с тем, что покажет Get-ADUser для этого пользователя. Различаться они не должны, и если различаются, перевыпуск обязателен. Не нужно спорить с этим фактом и искать, где «подправить»: сертификат с чужим SID для вашей учётной записи уже не действует, как бы красиво он ни выглядел в оснастке.
Проверка 4. Ручная привязка в altSecurityIdentities: какие форматы проходят
Если перевыпустить сертификат нельзя (токен без возможности перезаписи, сертификат от внешнего удостоверяющего центра, выпущенный на три года вперёд), остаётся ручная привязка. Атрибут altSecurityIdentities у учётной записи — это список строк, и обновление защиты разделило их на сильные и слабые. По KB5014754, слабые: X509IssuerSubject, X509SubjectOnly и X509RFC822 (то есть всё, что опирается на имена и адреса электронной почты), — они больше не защищают вход. Сильные: X509IssuerSerialNumber (Microsoft его рекомендует), X509SKI и X509SHA1PublicKey. Посмотреть, что реально записано у пользователя, можно так (для атрибута, не входящего в набор по умолчанию, в Properties указывают LDAP-имя):
Get-ADUser -Identity i.ivanova -Properties altSecurityIdentities | Select-Object -ExpandProperty altSecurityIdentitiesТипичная находка: в атрибуте лежит строка вида X509:<S>... или X509:<RFC822>..., созданная лет шесть назад ради какой-то одной системы. Для KDC такой записи как будто нет. Второй частый вариант: строка вроде бы сильная, но собрана с ошибкой. И здесь ошибаются практически все, кто собирает привязку руками. Серийный номер в записи нужно писать в обратном порядке байтов: по примеру из документации, для A1B2C3 получится C3B2A1, а не 3C2B1A, то есть переворачивать надо байты (пары символов), а не символы. Имя издателя в записи также идёт в обратном порядке RDN: в примере Microsoft это X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<SR>1200000000AC11000000002B. Если вы скопируете издателя из оснастки как есть, привязка не сработает, и никаких внятных подсказок система не даст.
Собирать строку руками я не советую: в человеческих глазах пары символов путаются. Скрипт ниже делает всё сам. Он учитывает, что издатель в .NET отдаётся в прямом порядке и со значениями через запятую с пробелом, поэтому для издателей с запятыми внутри значений его придётся доработать. Сначала проверьте результат на тестовой учётке, и только потом на рабочей.
$c = Get-Item Cert:\CurrentUser\My\<THUMBPRINT>
$sn = $c.SerialNumber
$rev = -join $(for ($i = $sn.Length - 2; $i -ge 0; $i -= 2) { $sn.Substring($i, 2) })
$rdn = $c.Issuer -split ', '
[array]::Reverse($rdn)
$map = "X509:<I>$($rdn -join ',')<SR>$rev"
Set-ADUser -Identity i.ivanova -Replace @{ altSecurityIdentities = $map }Обратите внимание на Replace: он перезаписывает весь атрибут целиком. Если у пользователя уже есть другие рабочие привязки, предварительно выгрузите их из Get-ADUser и включите в новое значение, иначе вы снесёте чужую настройку. Делегировать на запись этого атрибута широкому кругу лиц тоже не стоит: тот, кто может написать в altSecurityIdentities, фактически решает, чей сертификат считать вашим. Для 19 рабочих мест вопрос не стоит остро, но привычка — вещь заразная.
Как это выглядело в бухгалтерской консультации «Дебет-Кредит»
Условный пример из моей практики: бухгалтерская консультация «Дебет-Кредит», 19 рабочих мест, два контроллера домена, отдельный сервер с Enterprise CA, и у шести сотрудников вход в терминальный сервер и подпись документов привязаны к USB-токенам с доменными сертификатами. После сентябрьских обновлений 2025 года у четверых из шести вход пропал, у двоих продолжал работать. Приходит письмо от директора: сертификаты действуют до 2027 года, значит, ломает кто-то снаружи. Нет, ломает защита, причём вполне штатно.
Идём по порядку. Проверка 1: на втором контроллере за неделю накопились события Kdcsvc 39 по четырём учётным записям; на первом контроллере было пусто, потому что клиенты обращались ко второму, — вот и пример, почему журнал нужно читать везде. Проверка 2: параметр StrongCertificateBindingEnforcement в реестре обоих контроллеров нашёлся со значением 1, его создали в 2022 году. Мы его не трогали: на поведение он уже не влиял, зафиксировали и ушли дальше. Проверка 3: расширения с OID 1.3.6.1.4.1.311.25.2 у четырёх проблемных сертификатов нет, а у двух рабочих есть. Разница нашлась в шаблоне: четыре сертификата выданы по копии шаблона, где стоял бит 0x00080000 в msPKI-Enrollment-Flag, то есть расширение подавлялось. Проверка 4: у этих четверых в altSecurityIdentities лежали слабые записи X509:<S>..., и для KDC их фактически не существовало.
Что сделали: сняли флаг у шаблона, перевыпустили четыре сертификата на токены (по пятнадцать-двадцать минут на человека с проверкой входа), старые записи X509:<S> удалили после контрольного входа каждого. Диагностика заняла около трёх часов, перевыпуск и проверка — вторую половину рабочего дня. Ручные привязки не понадобились совсем, и это нормально: чем меньше ручных записей, тем меньше мусора будет жить в атрибутах через два года. Заодно через Zabbix повесили сбор событий Kdcsvc с контроллеров, чтобы следующая подобная проблема приходила не звонком директора, а алертом.
В каком порядке чинить и как не получить то же самое через год
Порядок решений из практики такой. Первым делом SID-расширение внутри сертификата: оно не требует ручной работы на каждого пользователя, переживает пересоздание атрибутов и не зависит от того, кто что записал в altSecurityIdentities. Это значит: проверить шаблоны, снять бит подавления, убедиться, что используется online-шаблон с субъектом из Active Directory, и перевыпустить сертификаты. Подробности про устройство центра сертификации и шаблонов у меня разложены в материале про AD Certificate Services и PKI, там же про то, почему не стоит ставить центр на контроллер домена. Вторым номером ручные привязки: точечно, для тех сертификатов, которые перевыпустить нельзя. Третьим — чистка слабых записей, но только после того, как вход у каждого проверен новой схемой.
Чего делать не нужно. Не продлевайте сертификат в надежде, что новый заработает: продление на старом шаблоне даст ту же картину. Не тащите ключи реестра из старых инструкций. Не раздавайте право записи в altSecurityIdentities помощникам администратора «чтобы быстрее». И не оставляйте CertificateMappingMethods в слабом режиме после диагностики. Всё это даёт ощущение работы, и всё это экономит ровно столько времени, сколько понадобится до следующего ночного звонка.
И последнее, самое скучное и самое полезное: мониторинг. События Kdcsvc 39, 40 и 41 на всех контроллерах должны попадать туда, где их кто-то видит. У нас это делается через мониторинг Active Directory в Zabbix, хватает одного правила на контроллер. Внимательность тут дешевле любого восстановления: бэкап делают все, а события безопасности читает почти никто.
Частые вопросы
Сертификат не просрочен и цепочка валидна, почему AD его отклоняет?
Срок и цепочка отвечают на вопрос о доверии, а контроллер домена дополнительно требует сильную привязку сертификата к учётной записи: SID-расширение в сертификате или сильную запись в altSecurityIdentities. Нет привязки — в журнале System появляется событие Kdcsvc 39.
Можно ли вернуть режим совместимости через StrongCertificateBindingEnforcement?
Нет. По документации Microsoft (KB5014754), с 9 сентября 2025 года возможность вернуться в режим совместимости закончилась, и этот ключ реестра больше не поддерживается. Нужно исправлять привязку, а не реестр.
Как понять, есть ли в сертификате SID-расширение?
Выгрузите сертификат в .cer и выполните certutil -dump с путём к файлу, затем найдите расширение с OID 1.3.6.1.4.1.311.25.2. Нет такого расширения — сертификат выдан без SID, и его нужно перевыпустить после исправления шаблона.
Какие записи в altSecurityIdentities считаются сильными?
X509IssuerSerialNumber (рекомендуется), X509SKI и X509SHA1PublicKey. Привязки по имени и почте (X509IssuerSubject, X509SubjectOnly, X509RFC822) слабые. В IssuerSerialNumber серийный номер пишется с обратным порядком байтов.
Нужно ли перевыпускать сертификаты после обновления центра сертификации?
Продление как таковое не требуется, но SID-расширение появится только в новых сертификатах: для ранее выданных нужен перевыпуск или сильная ручная привязка. Если сертификаты выдаёт не Enterprise CA от Microsoft, расширение само не появится.
Источники
- Microsoft KB5014754 — Хронология (10.05.2022 – 09.09.2025), режимы StrongCertificateBindingEnforcement, события Kdcsvc 39/40/41, OID 1.3.6.1.4.1.311.25.2, форматы altSecurityIdentities, CertificateMappingMethods: https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16
- Microsoft Learn: certutil — Синтаксис dump, verify и dsTemplate: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certutil
- Microsoft Learn: Get-ADUser — Параметры Identity, Filter, Properties, работа с LDAP-именами атрибутов: https://learn.microsoft.com/en-us/powershell/module/activedirectory/get-aduser
- Microsoft Learn: Get-WinEvent — Ключи FilterHashtable (LogName, ProviderName, Id, StartTime), параметр ComputerName: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.diagnostics/get-winevent
