Windows Server для самых маленьких. Часть 22: Как работает доверие между лесами?
Все части серии «Windows Server для самых маленьких»В прошлой части доверие между доменами одного леса появлялось само, было двусторонним и транзитивным, и его нельзя было ни настроить, ни отключить. Между лесами всё наоборот: доверия нет, пока его не создали, у него есть направление, тип, список суффиксов, фильтры и режимы, и каждый из этих параметров — ответ на вопрос «что чужой лес сможет делать в моём». Партнёрский лес в этой части — partner.example.net: компания, с которой нужно делить ресурсы, не сливая каталоги.
Все команды ниже выполняются с рабочей станции администратора ws1 в PowerShell 7 с RSAT (часть 15); то, что работает только на самом контроллере, идёт через Invoke-Command (часть 14). Наш лес — corp.example.com с контроллерами dc1, dc2, dc3 и dc4, PDC — dc1; у партнёра три контроллера: dc1, dc2 и dc3.partner.example.net. Между лесами уже есть двустороннее доверие, и всё, что его читает, показано с настоящим выводом. Команды, которые доверие создают или меняют, приведены по документации, без вывода.
Типы, направление, транзитивность
Направление. Доверие — отношение между двумя сторонами, и оно одностороннее по определению: доверяющий домен (trusting, на стороне ресурсов) принимает удостоверения пользователей доверенного (trusted, на стороне учётных записей). «Corp доверяет partner» означает: пользователи partner могут получать доступ к ресурсам corp, но не наоборот. Со стороны corp это исходящее доверие (outgoing: мы доверяем им), со стороны partner — входящее (incoming: нам доверяют). Двустороннее доверие — два односторонних.
Транзитивность. Транзитивное доверие распространяется дальше двух сторон: доверяя лесу partner, мы доверяем всем его доменам. Нетранзитивное — только одному домену, с которым создано.
Типы:
| Тип | С кем | Транзитивно | Аутентификация | Когда |
|---|---|---|---|---|
| Между лесами (forest) | корневой домен другого леса | да, на все домены обоих лесов | Kerberos и NTLM, маршрутизация суффиксов имён | основной тип между двумя лесами AD |
| Внешнее (external) | один домен другого леса (или домен NT 4.0) | нет | Kerberos и NTLM, только в этот домен, без маршрутизации суффиксов | когда нужен один домен, а не лес |
| Realm | realm Kerberos не от Microsoft (MIT, Heimdal, FreeIPA) | по выбору | только Kerberos | единый вход с Unix-инфраструктурой |
| Сокращающее (shortcut) | домен своего леса | да | Kerberos и NTLM | спрямить путь направляющих билетов в глубоком дереве |
Напомню, что делают протоколы из таблицы. Kerberos (часть 6) — билеты: клиент получает у KDC своего домена билет на службу, а если служба в чужом домене — направляющий билет (referral TGT, krbtgt/<чужой домен>), зашифрованный общим ключом двух доменов, с которым идёт к KDC того домена. NTLM — вызов-ответ: сервер передаёт ответ клиента своему контроллеру, тот по защищённому каналу Netlogon — контроллеру домена пользователя (сквозная аутентификация).
Доверие между лесами требует функционального уровня леса не ниже Windows Server 2003 с обеих сторон, то есть любого современного. Оно создаётся только между корневыми доменами двух лесов и на третий лес не распространяется: если corp доверяет partner, а partner — third.example.org, то corp лесу third не доверяет. Дальше речь о доверии между лесами; внешнее отличается областью действия и строгостью фильтрации SID.
DNS
Прежде чем KDC corp выдаст направляющий билет в partner, клиент должен найти контроллеры partner; прежде чем контроллер corp создаст доверие, он должен найти контроллеры partner, и наоборот. Каждый лес должен разрешать имена другого — не только partner.example.net, но и SRV-записи _msdcs.partner.example.net, по которым Locator находит контроллеры (часть 7).
Обычный способ — условный форвардер, хранимый в каталоге и реплицируемый на все DNS-серверы леса:
PS C:\> Add-DnsServerConditionalForwarderZone -ComputerName dc1 -Name partner.example.net -MasterServers 198.51.100.10, 198.51.100.11 -ReplicationScope Forest
Другой вариант, который тоже работает, — stub-зона: она хранит только записи SOA и NS зоны партнёра с адресами его DNS-серверов и сама обновляет их с этих серверов, поэтому при замене DNS-серверов партнёра список у нас меняется сам. Так выглядит stub-зона, хранимая в каталоге и реплицируемая на весь лес:
PS C:\> Get-DnsServerZone -CimSession dc1 -Name partner.example.net | Format-Table ZoneName, ZoneType, IsDsIntegrated, ReplicationScope, MasterServers -AutoSize
ZoneName ZoneType IsDsIntegrated ReplicationScope MasterServers
-------- -------- -------------- ---------------- -------------
partner.example.net Stub True Forest {198.51.100.10, 198.51.100.11}
Создаётся она Add-DnsServerStubZone -Name partner.example.net -MasterServers … -ReplicationScope Forest. Проверка с рабочей станции:
PS C:\> Resolve-DnsName _ldap._tcp.dc._msdcs.partner.example.net -Type SRV | Where-Object Type -eq SRV | Select-Object NameTarget, Port
NameTarget Port
---------- ----
dc2.partner.example.net 389
dc1.partner.example.net 389
dc3.partner.example.net 389
PS C:\> Resolve-DnsName dc1.partner.example.net | Select-Object IPAddress
IPAddress
---------
198.51.100.10
Без Where-Object Type -eq SRV в таблице появятся строки с пустым NameTarget: это записи A контроллеров из дополнительной секции ответа, у которых такого поля нет.
Партнёр делает то же самое для corp.example.com. Кроме DNS нужны время в пределах пяти минут между лесами (у Kerberos нет исключений для чужих realm, часть 12) и сеть: между контроллерами обоих лесов в обе стороны — LDAP 389, SMB 445, Kerberos 88, сопоставитель конечных точек RPC 135 и динамические порты RPC (через них идут LSA при создании доверия и Netlogon), от клиентов каждого леса к контроллерам другого — Kerberos 88 и LDAP 389.
Создание
В модуле ActiveDirectory из командлетов доверия есть только один:
PS C:\> Get-Command -Module ActiveDirectory *Trust*
CommandType Name
----------- ----
Cmdlet Get-ADTrust
New-ADTrust и Set-ADTrust нет. netdom trust, по документации, доверие между двумя лесами AD создать не может: им создают внешние доверия и доверия с realm, а у существующих — проверяют, сбрасывают ключ и меняют флаги. Доверие между лесами создают оснасткой «Active Directory Domains and Trusts» или классом .NET System.DirectoryServices.ActiveDirectory.Forest, который модуль не обернул. Если есть учётные данные администратора партнёра, доверие создаётся с обеих сторон одной командой, и пароль доверия обе стороны получают случайный:
PS C:\> $local = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
PS C:\> $cred = Get-Credential 'PARTNER\admin'
PS C:\> $ctx = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', 'partner.example.net', $cred.UserName, $cred.GetNetworkCredential().Password)
PS C:\> $remote = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ctx)
PS C:\> $local.CreateTrustRelationship($remote, 'Bidirectional')
TrustDirection принимает Inbound, Outbound, Bidirectional — с точки зрения своего леса. Обычный случай с партнёром, у которого свои администраторы и чьи учётные данные нам не дают, — по одной стороне, с общим паролем, который вводят оба администратора:
PS C:\> $local.CreateLocalSideOfTrustRelationship('partner.example.net', 'Outbound', (Read-Host 'Trust password'))
и у партнёра — CreateLocalSideOfTrustRelationship('corp.example.com', 'Inbound', <тот же пароль>). Этот пароль нужен только для установки доверия: дальше его меняет PDC доверяющей стороны раз в 30 дней (подробнее — в разделе о ключе доверия). Создавать доверие могут Domain Admins корневого домена или Enterprise Admins — с каждой стороны свои.
Внешнее доверие к одному домену партнёра создаётся netdom:
PS C:\> netdom trust corp.example.com /domain:partner.example.net /add /twoway /userD:PARTNER\admin /passwordD:* /userO:CORP\alice.admin /passwordO:*
Готовое доверие читает тот же класс:
PS C:\> $local.GetTrustRelationship('partner.example.net')
TopLevelNames : {partner.example.net}
ExcludedTopLevelNames : {}
TrustedDomainInformation : {partner.example.net}
SourceName : corp.example.com
TargetName : partner.example.net
TrustType : Forest
TrustDirection : Bidirectional
PS C:\> $local.GetSidFilteringStatus('partner.example.net')
True
PS C:\> $local.GetSelectiveAuthenticationStatus('partner.example.net')
False
Фильтрация SID включена, выборочная аутентификация — нет; что это значит, ниже. Тот же взгляд из модуля:
PS C:\> Get-ADTrust -Filter * | Format-Table Name, Direction, TrustType, ForestTransitive, SIDFilteringQuarantined, SIDFilteringForestAware, SelectiveAuthentication, TGTDelegation -AutoSize
Name Direction TrustType ForestTransitive SIDFilteringQuarantined SIDFilteringForestAware SelectiveAuthentication TGTDelegation
---- --------- --------- ---------------- ----------------------- ----------------------- ----------------------- -------------
partner.example.net BiDirectional Uplevel True False False False False
Здесь легко ошибиться: SIDFilteringForestAware: False не означает, что фильтрации нет. Это свойство показывает бит TREAT_AS_EXTERNAL (о нём ниже), который фильтрацию у доверия между лесами ослабляет; False — фильтрация полная, и GetSidFilteringStatus выше честно отвечает True. SIDFilteringQuarantined — бит карантина, который ставят внешним довериям, у доверия между лесами он False. TGTDelegation: False — делегирование TGT через доверие явно не разрешено, то есть запрещено.
Netlogon видит доверие так:
PS C:\> nltest /trusted_domains
List of domain trusts:
0: PARTNER partner.example.net (NT 5) (Direct Outbound) (Direct Inbound) ( Attr: foresttrans )
1: CORP corp.example.com (NT 5) (Forest Tree Root) (Primary Domain) (Native)
The command completed successfully
nltest /domain_trusts /all_trusts /v выдаёт тот же список и добавляет SID и GUID доменов. Защищённый канал к домену партнёра держит каждый контроллер, и смотреть его нужно на контроллере, а не на рабочей станции:
PS C:\> nltest /server:dc1 /sc_query:partner.example.net
Flags: 30 HAS_IP HAS_TIMESERV Authentication Service: Netlogon
Trusted DC Name \\dc3.partner.example.net
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully
PS C:\> nltest /sc_query:partner.example.net
I_NetLogonControl failed: Status = 1355 0x54b ERROR_NO_SUCH_DOMAIN
У рабочей станции защищённый канал только к своему домену, поэтому без /server: ответ — «нет такого домена». /sc_query только читает состояние канала (о нём — в части 18); nltest /sc_verify:partner.example.net и netdom trust corp.example.com /domain:partner.example.net /verify /kerberos по документации проверяют доверие активно и при неработающем канале пересоздают его, поэтому их запускают, когда что-то уже сломано.
Объект доверия
Каждое доверие — объект trustedDomain в CN=System, как в прошлой части, но с другими битами в trustAttributes. В скобках — свойства Get-ADTrust, которые модуль вычисляет из этих битов:
| Бит | Имя | Что |
|---|---|---|
| 0x1 | NON_TRANSITIVE | нетранзитивное (внешнее) (DisallowTransivity) |
| 0x2 | UPLEVEL_ONLY | только для клиентов Windows 2000 и новее (UplevelOnly) |
| 0x4 | QUARANTINED_DOMAIN | карантин: строгая фильтрация SID у внешнего доверия (SIDFilteringQuarantined) |
| 0x8 | FOREST_TRANSITIVE | доверие между лесами (ForestTransitive) |
| 0x10 | CROSS_ORGANIZATION | выборочная аутентификация (SelectiveAuthentication) |
| 0x20 | WITHIN_FOREST | внутри леса (IntraForest) |
| 0x40 | TREAT_AS_EXTERNAL | доверие между лесами, но фильтрация SID ослаблена до внешнего (SIDFilteringForestAware) |
| 0x80 | USES_RC4_ENCRYPTION | realm-доверие с MIT Kerberos, умеющим RC4 (UsesRC4Encryption) |
| 0x100 | USES_AES_KEYS | TGT через доверие шифруются AES (UsesAESKeys) |
| 0x200 | CROSS_ORGANIZATION_NO_TGT_DELEGATION | делегирование TGT запрещено; после обновлений 2019 года вместо него действует 0x800 |
| 0x400 | PIM_TRUST | вместе с 0x40 — доверие с лесом привилегированного доступа (PIM), со своими правилами фильтрации SID |
| 0x800 | CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION | делегирование TGT явно разрешено (TGTDelegation) |
| 0x1000 | DISABLE_AUTH_TARGET_VALIDATION | отключена проверка имени домена при сквозной аутентификации NTLM |
PIM (Privileged Identity Management) — схема, в которой учётные записи администраторов живут в отдельном защищённом лесу, а в рабочем лесу получают права через такое доверие на время.
PS C:\> $t = Get-ADObject -Filter 'objectClass -eq "trustedDomain" -and Name -eq "partner.example.net"' -SearchBase 'CN=System,DC=corp,DC=example,DC=com' -Properties trustPartner, flatName, trustType, trustDirection, trustAttributes, msDS-SupportedEncryptionTypes
PS C:\> $t | Format-List trustPartner, flatName, trustType, trustDirection, trustAttributes, msDS-SupportedEncryptionTypes
trustPartner : partner.example.net
flatName : PARTNER
trustType : 2
trustDirection : 3
trustAttributes : 8
msDS-SupportedEncryptionTypes : 24
PS C:\> '0x{0:X}' -f $t.trustAttributes
0x8
trustType 2 — домен Active Directory (1 — домен NT 4.0, 3 — realm MIT); trustDirection 3 — двустороннее (1 — входящее, 2 — исходящее); trustAttributes 0x8 — только FOREST_TRANSITIVE. Бита NO_TGT_DELEGATION нет, и это нормально: обновления 2019 года не выставляют его, а меняют умолчание — без бита 0x800 пересланные TGT через доверие не ходят. msDS-SupportedEncryptionTypes 24 (0x18) — AES128 и AES256, о ключе доверия ниже. У доверия между лесами есть ещё двоичный атрибут msDS-TrustForestTrustInfo со списком суффиксов партнёра — следующий раздел.
Ключ доверия лежит в атрибутах trustAuthIncoming и trustAuthOutgoing этого объекта; читать их не нужно и не стоит, а у входящего доверия есть ещё парная учётная запись с именем домена партнёра и $ на конце:
PS C:\> Get-ADObject -LDAPFilter '(sAMAccountName=PARTNER$)' -Properties sAMAccountType, userAccountControl, pwdLastSet | Format-List DistinguishedName, @{n='sAMAccountType'; e={'0x{0:X}' -f $_.sAMAccountType}}, @{n='userAccountControl'; e={'0x{0:X}' -f $_.userAccountControl}}, @{n='pwdLastSet'; e={[datetime]::FromFileTime($_.pwdLastSet)}}
DistinguishedName : CN=PARTNER$,CN=Users,DC=corp,DC=example,DC=com
sAMAccountType : 0x30000002
userAccountControl : 0x820
pwdLastSet : 28.10.2026 16:26:12
sAMAccountType 0x30000002 — учётная запись доверия, в userAccountControl 0x800 — INTERDOMAIN_TRUST_ACCOUNT (и 0x20, пароль не обязателен по политике). Удалять или переименовывать её руками нельзя: она часть доверия.
Суффиксы имён
Пользователь bob@partner.example.net вводит свой UPN на рабочей станции corp, или клиент corp просит билет на cifs/fs1.partner.example.net. Контроллер corp должен понять, в какой лес отправить запрос. Для этого у доверия между лесами есть маршрутизация суффиксов имён (name suffix routing): при создании доверия каждый лес собирает у партнёра его пространства имён — имена деревьев доменов, UPN- и SPN-суффиксы, SID доменов — и хранит их в msDS-TrustForestTrustInfo объекта доверия. Объекты доверия реплицируются в глобальный каталог (часть 10), и когда KDC не находит SPN в своём лесу, глобальный каталог сравнивает его суффикс со списками доверий и возвращает подсказку, в какой лес отправить клиента.
PS C:\> $local.GetTrustRelationship('partner.example.net').TopLevelNames
Name Status
---- ------
partner.example.net Enabled
У нашего партнёра один уникальный суффикс — имя его леса; дочерние домены и имена вида *.partner.example.net маршрутизируются вместе с ним. Состояние суффикса — одно из четырёх: Enabled, NewlyCreated, AdminDisabled, ConflictDisabled. При создании доверия все уникальные суффиксы включены, а новый уникальный суффикс, который партнёр добавит потом (UPN-суффикс, новое дерево), появится после проверки доверия, но маршрутизироваться не будет, пока администратор доверяющей стороны его не включит.
Конфликт суффиксов возникает, когда то же DNS-имя, NetBIOS-имя или SID домена уже встречается в нашем лесу или у другого доверенного леса: тогда суффикс в новом доверии отключается, и маршрутизироваться в лес партнёра он не будет. Например, если corp использует альтернативный UPN-суффикс example.org, а у партнёра он тоже есть, то вход alice@example.org из corp к партнёру не уйдёт. Отсюда частая картина: вход по UPN через доверие не работает, а по PARTNER\bob работает. Список суффиксов в netdom:
PS C:\> netdom trust corp.example.com /namesuffixes:partner.example.net
PS C:\> netdom trust corp.example.com /namesuffixes:partner.example.net /togglesuffix:2
Первая команда нумерует суффиксы, вторая включает или выключает суффикс с этим номером. Нумерация может меняться, поэтому /togglesuffix запускают сразу после /namesuffixes, а суффикс в конфликте можно включить только после того, как его выключили в другом доверии. Отключённый суффикс — отключённый путь: имена под ним через доверие не маршрутизируются.
Фильтрация SID
Из прошлой части: внутри леса контроллеры не проверяют, откуда взялся SID в sIDHistory или в группах пользователя. Между лесами проверяют, и это называется фильтрацией SID (SID filtering): контроллер доверяющего леса, получив через доверие билет с PAC или ответ на сквозную аутентификацию NTLM, вычёркивает из списка SID те, что доверенный лес заявлять не вправе. У доверия между лесами пропускаются только SID доменов леса партнёра (тех, что записаны в msDS-TrustForestTrustInfo). SID из sIDHistory, указывающий на группу Enterprise Admins нашего леса, будет удалён, даже если администратор партнёра старательно его туда записал; удаляются и SID третьих лесов, и служебные SID вроде S-1-5-9 (Enterprise Domain Controllers): контроллеры чужого леса нашими контроллерами не становятся.
Каждый такой случай контроллер пишет в журнал Security событием 4675 «SIDs were filtered» (подкатегория аудита Logon). У нас оно встречается регулярно:
PS C:\> Invoke-Command -ComputerName dc3, dc4 -ScriptBlock {
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4675} -ErrorAction SilentlyContinue |
ForEach-Object { ([xml]$_.ToXml()).Event.EventData.Data | Where-Object Name -eq SidList | ForEach-Object { $_.'#text'.Trim() } } |
Group-Object -NoElement
} | Format-Table PSComputerName, Count, Name -AutoSize
PSComputerName Count Name
-------------- ----- ----
dc3 8 %{S-1-5-9}
dc4 14 %{S-1-5-9}
Во всех событиях вычеркнут один SID — S-1-5-9, а учётная запись — компьютер из домена партнёра: контроллер партнёра обращался к нашему, и его принадлежность к Enterprise Domain Controllers своего леса у нас отброшена. Так фильтр и должен работать; событие 4675 с другими SID, особенно с SID наших групп, — повод выяснить, кто их туда записал.
Внешнее доверие фильтрует строже или мягче — смотря по биту QUARANTINED_DOMAIN. С карантином (netdom trust … /quarantine:Yes) проходят только SID самого доверенного домена; контроллеры, начиная с Windows Server 2003 и Windows 2000 SP4, ставят карантин всем новым внешним довериям сами.
Ослабить фильтрацию у доверия между лесами можно битом TREAT_AS_EXTERNAL: netdom trust corp.example.com /domain:partner.example.net /EnableSIDHistory:Yes. Тогда доверие фильтруется как внешнее, и SID из sIDHistory пользователей партнёра, созданные администраторами (RID от 1000), проходят. Встроенные привилегированные группы нашего леса — Domain Admins, Enterprise Admins и другие с RID меньше 1000 — отсекаются и в этом режиме, но любая наша собственная группа, например группа с правами администратора на серверах, становится доступна администратору партнёра: он может вписать её SID в sIDHistory своей учётной записи. Причина включать это одна — миграция пользователей из партнёрского леса с сохранением старых SID, чтобы права на ресурсы продолжали работать до переназначения. На время миграции и обратно (/EnableSIDHistory:No) — сразу после. Признак ослабленного доверия — SIDFilteringForestAware: True у Get-ADTrust.
Выборочная аутентификация
По умолчанию доверие между лесами даёт аутентификацию по всему лесу (forest-wide): любой пользователь partner может аутентифицироваться на любой машине corp. Прав на ресурсы у него от этого нет — но сервер, на котором он аутентифицировался, добавляет ему в токен Authenticated Users своего леса, а эта группа встречается в правах на общие папки, в правах по умолчанию на объекты каталога и в группе Pre-Windows 2000 Compatible Access, которой разрешено читать учётные записи. Партнёрский лес с сотней человек, которые ни в чём не виноваты, получает возможность читать наш каталог целиком.
Выборочная аутентификация (selective authentication) меняет умолчание: пользователь partner может аутентифицироваться только на тех машинах corp, на учётных записях которых ему или его группе явно выдано расширенное право Allowed to Authenticate. Включают её на доверяющей стороне, для исходящего доверия:
PS C:\> netdom trust corp.example.com /domain:partner.example.net /SelectiveAUTH:Yes
То же — $local.SetSelectiveAuthenticationStatus('partner.example.net', $true). Право выдаётся на объекте компьютера в каталоге, а не на самом сервере. Его GUID берётся из CN=Extended-Rights раздела конфигурации:
PS C:\> Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).configurationNamingContext)" -LDAPFilter '(displayName=Allowed to Authenticate)' -Properties rightsGuid | Format-List Name, rightsGuid
Name : Allowed-To-Authenticate
rightsGuid : 68B1D179-0D15-4d4f-AB71-46152E79A7BC
PS C:\> $acl = Get-Acl 'AD:\CN=FS1,OU=Servers,DC=corp,DC=example,DC=com'
PS C:\> $sid = (Get-ADGroup -Identity 'Partner Project Team' -Server partner.example.net).SID
PS C:\> $allowedToAuth = [Guid]'68b1d179-0d15-4d4f-ab71-46152e79a7bc'
PS C:\> $acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule($sid, 'ExtendedRight', 'Allow', $allowedToAuth)))
PS C:\> Set-Acl 'AD:\CN=FS1,OU=Servers,DC=corp,DC=example,DC=com' -AclObject $acl
Теперь группа партнёра аутентифицируется на fs1 и больше нигде; права на папки fs1 выдаются ей обычным образом, через доменно-локальную группу corp, как в следующей части. Если служба работает не от имени компьютера, а под доменной учётной записью (SQL Server под svc-sql), для Kerberos право выдаётся на этой учётной записи; для NTLM — всегда на компьютере.
Как это работает: контроллер корневого домена corp, получив запрос через доверие с выборочной аутентификацией, добавляет пользователю в данные авторизации SID S-1-5-1000 — Other Organization. Контроллер, выдающий сервисный билет на fs1, видит этот SID, проверяет право Allowed to Authenticate на объекте fs1 и без него билет не выдаёт. Свои пользователи и пользователи доверий без выборочной аутентификации получают на серверах вместо него S-1-5-15 — This Organization:
PS C:\> whoami /groups /fo csv | ConvertFrom-Csv | Where-Object 'Group Name' -match 'Organization' | Select-Object 'Group Name', SID
Group Name SID
---------- ---
NT AUTHORITY\This Organization S-1-5-15
У пользователя партнёра при выборочной аутентификации на этом месте будет NT AUTHORITY\Other Organization — по нему права можно выдавать или запрещать отдельно.
Для доверия с партнёром, с которым делят два сервера, выборочная аутентификация — правильное умолчание. Для доверия между двумя лесами одной компании, где пользователи ходят куда угодно, — лишняя работа.
Делегирование через доверие
Третий параметр безопасности — делегирование TGT. Неограниченное делегирование из части 6 пересылает TGT пользователя серверу; через доверие это означало бы, что сервер партнёра получает TGT нашего пользователя и может действовать от его имени где угодно у нас. После обновлений 2019 года (KB4490425) пересланные TGT через входящие доверия между лесами и внешние доверия по умолчанию не выдаются — и у новых, и у существующих доверий, без всякой настройки. Разрешает их только бит ENABLE_TGT_DELEGATION, который ставит netdom trust corp.example.com /domain:partner.example.net /EnableTGTDelegation:Yes, и Get-ADTrust показывает его как TGTDelegation: True. Клиент тоже знает о запрете: в klist у билетов в лес партнёра стоит флаг кеша DISABLE-TGT-DELEGATION (вывод — в «Смотрим руками»).
Если партнёрское приложение действительно требует неограниченного делегирования для пользователей другого леса — это повод переделать его на делегирование на основе ресурса, которое работает через доверие и TGT не пересылает. /EnableTGTDelegation:Yes стоит воспринимать как отключение защиты; у доверия с карантином включить его нельзя вовсе.
Ключ доверия и AES
Ключ доверия — общий пароль двух сторон, из которого получаются ключи Kerberos для направляющих билетов, и у него, как у любого принципала Kerberos, есть типы шифрования. Тип шифрования направляющего билета KDC выбирает по клиенту и доверию, а не по клиенту и службе. Исторически доверие поддерживало RC4, и клиент, которому оставили только AES, к службам в лесу партнёра не попадал: KDC отвечал KDC_ERR_ETYPE_NOSUPP. Документация здесь расходится: статья об этой ошибке говорит, что по умолчанию доверие поддерживает RC4, а описание события 4769 — что после обновлений для контроллеров и доверий AES поддерживается по умолчанию, пока атрибут не меняли вручную. Чтобы не зависеть от умолчаний, типы шифрования задают на объекте доверия явно, с обеих сторон — каждый администратор на своей:
PS C:\> ksetup /setenctypeattr partner.example.net AES128-CTS-HMAC-SHA1-96 AES256-CTS-HMAC-SHA1-96
ksetup работает с объектом доверия через локальную LSA контроллера, поэтому запускается на контроллере; с рабочей станции он отвечает ошибкой:
PS C:\> ksetup /getenctypeattr partner.example.net
Query of attributes on partner.example.net failed with 0xc0000034
Failed /GetEncTypeAttr : 0xc0000034
PS C:\> Invoke-Command -ComputerName dc1 -ScriptBlock { ksetup /getenctypeattr partner.example.net }
Enctypes for domain partner.example.net: AES128-CTS-HMAC-SHA1-96 AES256-CTS-HMAC-SHA1-96
То же — флажок «The other domain supports Kerberos AES Encryption» в свойствах доверия, а в каталоге — значение 24 (0x18) в msDS-SupportedEncryptionTypes объекта доверия, которое мы видели выше. Если клиенты ещё пользуются RC4, к списку добавляют RC4-HMAC-MD5.
Пароль доверия меняется сам: раз в 30 дней PDC доверяющей стороны (часть 17) создаёт новый, сохраняет прежний рядом и по защищённому каналу просит контроллер доверенной стороны записать новый у себя. У двустороннего доверия это происходит дважды, для каждого направления отдельно. Видно это по метаданным репликации объекта доверия:
PS C:\> Get-ADReplicationAttributeMetadata -Object $t -Server dc1 -Properties trustAuthIncoming, trustAuthOutgoing, msDS-SupportedEncryptionTypes, trustAttributes | Format-Table AttributeName, LastOriginatingChangeTime, Version -AutoSize
AttributeName LastOriginatingChangeTime Version
------------- ------------------------- -------
msDS-SupportedEncryptionTypes 09.09.2026 15:21:17 1
trustAttributes 20.12.2022 19:33:09 1
trustAuthOutgoing 28.10.2026 16:26:12 47
trustAuthIncoming 24.10.2026 19:51:04 47
Доверию почти четыре года, и у каждого ключа 47-я версия — по смене в месяц. Исходящий ключ (мы доверяем партнёру, PDC — наш) и входящий (меняет PDC партнёра) обновились в разные дни. trustAttributes с создания не менялся ни разу, а AES включили позже — это видно по дате у msDS-SupportedEncryptionTypes. Значения самих ключей командлет не показывает: метаданные — это только кто, когда и какая версия.
Realm
Доверие с realm Kerberos без Active Directory — MIT Kerberos или Heimdal на Linux, FreeIPA (каталог с Kerberos для Linux) — создаётся netdom как обмен общим ключом:
PS C:\> netdom trust corp.example.com /domain:EXAMPLE.ORG /add /realm /passwordT:*
PS C:\> ksetup /addkdc EXAMPLE.ORG kdc1.example.org
PS C:\> ksetup /setenctypeattr EXAMPLE.ORG AES256-CTS-HMAC-SHA1-96
На стороне MIT — kadmin addprinc krbtgt/CORP.EXAMPLE.COM@EXAMPLE.ORG с тем же паролем. Пользователи realm не существуют в каталоге, и чтобы alice@EXAMPLE.ORG могла открыть папку в corp, её принципал сопоставляют с учётной записью: Set-ADUser alice-ext -Add @{ altSecurityIdentities = 'Kerberos:alice@EXAMPLE.ORG' }. Чужой KDC не кладёт в билет PAC, групп из другого realm нет, NTLM через такое доверие не ходит — только Kerberos и только то, что сопоставлено. В части 30 к этому механизму мы вернёмся с Linux-стороны.
Обслуживание
Если смена пароля доверия не дошла до партнёра (сеть лежала, защищённый канал не поднялся), доверяющий контроллер продолжает пользоваться старым паролем и через 15 минут пробует снова; ломается доверие, когда у одной стороны не остаётся ни нового, ни прежнего пароля другой. Тогда у пользователей — ошибка 1788 «The trust relationship between the primary domain and the trusted domain failed.», а в журнале System контроллеров — события Netlogon: 5719 («This computer was not able to set up a secure session with a domain controller in domain …») у того, кто не может поднять защищённый канал, и 5805 или 5722 («The session setup from the computer … failed to authenticate») у того, к кому он не смог подключиться.
Проверка и починка — по документации: netdom trust corp.example.com /domain:partner.example.net /verify и /reset с учётными данными обеих сторон (/userD, /passwordD, /userO, /passwordO), у доверия между лесами — ещё $local.RepairTrustRelationship($remote). Без учётных данных партнёра каждая сторона задаёт общий пароль заново у себя: $local.UpdateLocalSideOfTrustRelationship('partner.example.net', <новый пароль>) у нас и то же у партнёра.
Удаление — $local.DeleteTrustRelationship($remote) (обе стороны) или netdom trust corp.example.com /domain:partner.example.net /remove. Если партнёр уже удалил свою сторону и у нас остался объект trustedDomain, его убирает $local.DeleteLocalSideOfTrustRelationship('partner.example.net') или netdom … /remove /oneside:trusting.
Смотрим руками
Путь билета через доверие, глазами клиента corp, которому нужна шара на контроллере партнёра:
PS C:\> klist get cifs/dc1.partner.example.net | Select-String 'retrieved'
A ticket to cifs/dc1.partner.example.net has been retrieved successfully.
PS C:\> klist | Select-String 'Server: (krbtgt/PARTNER|cifs/dc1.partner)' -Context 1,9
#0> Client: alice.admin @ CORP.EXAMPLE.COM
> Server: krbtgt/PARTNER.EXAMPLE.NET @ CORP.EXAMPLE.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 10/29/2026 15:03:45 (local)
End Time: 10/30/2026 1:03:45 (local)
Renew Time: 11/5/2026 13:28:12 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x200 -> DISABLE-TGT-DELEGATION
Kdc Called: dc1.corp.example.com
#3> Client: alice.admin @ CORP.EXAMPLE.COM
> Server: cifs/dc1.partner.example.net @ PARTNER.EXAMPLE.NET
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a50000 -> forwardable renewable pre_authent ok_as_delegate name_canonicalize
Start Time: 10/29/2026 15:03:45 (local)
End Time: 10/30/2026 1:03:45 (local)
Renew Time: 11/5/2026 13:28:12 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x200 -> DISABLE-TGT-DELEGATION
Kdc Called: dc3.partner.example.net
klist get сам печатает весь кеш после строки об успехе, поэтому нужные билеты выбраны отдельно. Направляющий билет krbtgt/PARTNER.EXAMPLE.NET выдан нашим KDC (@ CORP.EXAMPLE.COM, Kdc Called: dc1) и зашифрован ключом доверия — AES-256, потому что на доверии включён AES. Сервисный билет выдал уже KDC партнёра (dc3.partner.example.net), и в нём флаг ok_as_delegate — служба партнёра доверена для делегирования. Но у обоих билетов флаг кеша DISABLE-TGT-DELEGATION: свой TGT клиент службам партнёра пересылать не станет.
На нашем контроллере этот запрос — событие 4769, где служба — сам домен партнёра:
PS C:\> Invoke-Command -ComputerName dc1 -ScriptBlock {
$e = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4769; StartTime=(Get-Date).AddMinutes(-60)} |
Where-Object { $_.Properties[2].Value -eq 'PARTNER.EXAMPLE.NET' } | Select-Object -First 1
$d = [ordered]@{}; ([xml]$e.ToXml()).Event.EventData.Data | ForEach-Object { $d[$_.Name] = $_.'#text' }
'ServiceName','TicketEncryptionType','Status','ServiceSupportedEncryptionTypes','ServiceAvailableKeys' | ForEach-Object { '{0,-32}: {1}' -f $_, $d[$_] }
}
ServiceName : PARTNER.EXAMPLE.NET
TicketEncryptionType : 0x12
Status : 0x0
ServiceSupportedEncryptionTypes : 0x18 (AES128-SHA96, AES256-SHA96)
ServiceAvailableKeys : AES128-SHA96, AES256-SHA96
0x12 — AES256, 0x18 — типы, разрешённые на доверии, и ключи AES у него есть. Если бы на доверии остался только RC4, здесь было бы 0x17, а у клиента без RC4 — отказ.
Все доверия леса с их параметрами, одной таблицей:
PS C:\> Get-ADTrust -Filter * -Properties * | Format-Table Name, Direction, ForestTransitive, SelectiveAuthentication, SIDFilteringForestAware, TGTDelegation, @{n='EncTypes'; e={$_.'msDS-SupportedEncryptionTypes'}}, Created -AutoSize
Name Direction ForestTransitive SelectiveAuthentication SIDFilteringForestAware TGTDelegation EncTypes Created
---- --------- ---------------- ----------------------- ----------------------- ------------- -------- -------
partner.example.net BiDirectional True False False False 24 20.12.2022 19:33:09
В лесу с дочерними доменами здесь будут и доверия внутри леса — их отличает IntraForest: True. Эту таблицу стоит получать раз в месяц: доверие, у которого SIDFilteringForestAware или TGTDelegation стали True, у внешнего доверия SIDFilteringQuarantined стал False, а у партнёрского пропала выборочная аутентификация, — вопрос к тому, кто его менял.
Источники
Доверия:
- How trusts work for Microsoft Entra Domain Services — направление и транзитивность, доверие между лесами только через корневые домены и без продолжения на третий лес, требования к DNS, Kerberos через доверие и подсказки глобального каталога, смена пароля доверия раз в 30 дней;
- How Domain and Forest Trusts Work — объект доверия, пароль доверия у PDC доверяющей стороны, повтор через 15 минут, порты для доверий;
- Security Considerations for Trusts — фильтрация SID, карантин внешних доверий,
/EnableSIDHistory, выборочная аутентификация, Other Organization и This Organization; - Enable Selective Authentication over a Forest Trust — включение выборочной аутентификации и право Allowed to Authenticate;
- Routing name suffixes across forests — уникальные суффиксы, новые суффиксы выключены, конфликты имён;
- Updates to TGT delegation across incoming trusts in Windows Server — запрет делегирования TGT через доверия по умолчанию и
/EnableTGTDelegation; - "Unsupported etype" error when accessing a resource in a trusted domain — выбор шифрования направляющего билета по доверию, RC4 по умолчанию,
ksetup /setenctypeattr; - Configure firewall for AD domain and trusts — порты между лесами.
Спецификации и схема:
- MS-ADTS: trustAttributes — биты атрибута и их смысл;
- MS-ADTS: Essential Attributes of a Trusted Domain Object — атрибуты объекта доверия;
- MS-PAC: SID Filtering and Claims Transformation — правила фильтрации SID для доверий между лесами, внешних и карантинных доверий,
S-1-5-9, RID меньше 1000; - Allowed-To-Authenticate — расширенное право и его GUID;
- Security identifiers — Enterprise Domain Controllers, This Organization, Authenticated Users из доверенных доменов, Pre-Windows 2000 Compatible Access;
- UserAccountControl property flags — флаг INTERDOMAIN_TRUST_ACCOUNT, значение 0x820 у учётной записи доверия.
Команды:
- Get-ADTrust — чтение доверий модулем;
- Forest Class —
CreateTrustRelationship,CreateLocalSideOfTrustRelationship,GetTrustRelationship,GetSidFilteringStatus,SetSelectiveAuthenticationStatus,RepairTrustRelationship,DeleteLocalSideOfTrustRelationship; - TopLevelNameStatus Enum — состояния суффиксов;
- Netdom trust — создание внешних и realm-доверий,
/verify,/reset,/namesuffixes,/quarantine,/EnableSIDHistory,/SelectiveAuth,/EnableTgtDelegation; - Nltest —
/trusted_domains,/domain_trusts,/sc_query,/sc_verify; - ksetup setenctypeattr и ksetup getenctypeattr — типы шифрования доверия;
- klist —
klist getи кеш билетов; - Add-DnsServerConditionalForwarderZone и Add-DnsServerStubZone — DNS для леса партнёра;
- Resolve-DnsName — проверка SRV-записей партнёра;
- Get-ADReplicationAttributeMetadata — метаданные атрибутов объекта доверия;
- 4675(S): SIDs were filtered и 4769(S, F): A Kerberos service ticket was requested — события фильтрации SID и выдачи билетов, коды типов шифрования, AES по умолчанию для доверий.
Доверие создано, фильтры включены, суффиксы маршрутизируются. Пользователь партнёра может аутентифицироваться на fs1 — но прав у него там по-прежнему нет, и выдать их не так просто, как кажется.
Дальше — часть 23: доступ через доверие на практике. Какие группы принимают членов из чужого леса, а какие нет, и почему встроенная группа Administrators не примет доменно-локальную; схема выдачи прав на файловые ресурсы, на серверы, на SQL Server и RDP пользователям другого леса; как выглядят чужие пользователи в каталоге — foreignSecurityPrincipals; и что проверять, когда «доступ есть, а не пускает».
Оставить комментарий могут только зарегистрированные пользователи.
Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.