Группы Windows NT и Active Directory

Local и Domain Local, Global и Universal, Security и Distribution - вокруг них много фантазий и мифов. Разбираемся.

Для человека, который сталкивается с многообразием групп в Active Directory, разобраться с ними сходу весьма трудно. Local и Domain Local, Global и Universal, Security и Distribution – всё это осложняется ситуацией “кого в кого можно включать”, и в финале сопровождается выводом “нафиг столько нагородили, уму непостижимо”. Добавляет к этому бардаку сочности то, что в фирменных курсах Microsoft данная тема освещается всё обзорнее и обзорнее – и сводится буквально к паре слайдов “запомните вот эту табличку”, без объяснения причин того, почему всё работает именно так.
Такой подход понятен – задача Microsoft – максимально удешевить чтение курсов, снижая требования по знаниям у MCT, которые обычно сами не могут объяснить, почему с группами в Windows / Active Directory всё сложилось именно так. Нужен меньший уровень знаний, чтобы вслух ртом начитывать сверху вниз слайды – можно меньше платить – ниже расходы – выше прибыль у партнёров Microsoft – больше партнёров – больше прибыли Microsoft. Приводит это к предсказуемому результату – тему “проскакивают” на бегу с логикой “зазубрите табличку, потом дампы почитаете чуток и проходной балл на экзамене кое-как перевалите, да вообще всё это некритично на самом деле”, а после работают с группами наощупь, а-ля “я на форуме читал, что всё надо делать security global, а у distribution SID’а вообще нет, ко-ко-ко”, ну и с подобными мифами. Табличка “кого в куда включать можно”, будучи не понятой, быстро забывается, а вся тема остаётся мистическим облачком “ой там всё мутно, нереально разобраться, да и не нужно никому”.

Группы Windows NT и Active Directory – что, зачем, как, почему

  • Часть первая – изначальная ситуация – одиночная система
  • Часть вторая – домен Windows NT – появление Domain Local и Security-групп
  • Лирическое отступление про максимальное количество групп и прочие технические мелочи
  • Поведение системы при переполнении маркера доступа
  • Часть третья – лес Active Directory – появление Universal-групп и разделения на Security и Distribution
  • Universal-группы и режимы работы домена
  • Можно ли жить в лесу Active Directory без Universal-групп, только с Global и Domain Local
  • Проблемы масштабирования при использовании только Global и Domain Local
  • Domain Local-группы и объекты Active Directory
  • Миф про сниженное быстродействие Universal-групп
  • Миф про одинаковость всех групп, потому что их можно друг в друга переключать
Приступим.

Часть первая – изначальная ситуация – одиночная система

Группы, как объекты, являющиеся участниками системы безопасности – т.н. “security principal” – появились в Windows NT изначально. Так же как и пользователи, группы имеют свой личный и уникальный в пределах системы идентификатор – SID
Однако, даже на единичной системе групп уже есть два вида – это встроенные, например BUILTIN\Administrators, и дополнительно созданные – в моём случае это группа TestLocalGroup и некоторые другие:
Как отличить эти два типа групп? Исключая, конечно, то, что мне было лень писать description к тестовой группе, и она выделяется по этому признаку? Всё просто – у этих двух типов групп разные форматы SID’ов:
У встроенных это будет S-1-5-32-xxx, где XXX – идентификатор от 500 до 1000 (в теории, в реальности полтыщи встроенных групп в системе нет, их меньше полусотни). У обычных это будет S-1-5-21-yyy-zzz, где YYY – это идентификатор системы (его меняет, например, утилита sysprep), а ZZZ – это RID.
Встроенные группы будут стоять особняком – они нужны для предоставления прав учётным записям, исключительно – т.е. ни включать их друг в друга (эта операция будет называться group nesting), ни включать в них обычные локальные группы будет нельзя. Вы можете убедиться в этом, запросив на локальной системе список тех, кто может быть добавлен во встроенную группу:
Если что, ATRAINING-DEMO – это имя локальной машины, это обычная Windows 8.1, разве что на ней заведена учётка пользователя с именем Ruslan.
Т.е. задача этих групп – выдавать права тем или иным локальным пользователям или обладателям каких-то специфичных SID’ов в nt-маркере доступа – например, logon type’ов типа NETWORK или INTERACTIVE.
Возможность же создавать свои собственные группы на локальной машине нужна, чтобы предоставлять доступ к ресурсам – например, общим папкам. Вы можете создавать группы, и включать в них пользователей. Ранее, замечу, можно было включать локальные группы в локальные – для этого трюка нужна утилита net.exe и её контекст LOCALGROUP, но на данный момент этот функционал заблокирован и даже если вы сделаете так на NT 4.0 и проапгрейдите систему до современной версии, то все равно – lsass учитывает у локальных пользователей только группы, в которые они включены напрямую, т.е. в маркере доступа других групп не будет.
Зачем же в этой ситуации, когда можно было бы обойтись, по сути, простым критерием “RID меньше тысячи – значит, встроенная группа – а больше – значит, созданная пользователем”, делать разные форматы SID’ов? Нужно это было для того, чтобы обеспечить перенос ACL’ов между системами. Пример – у вас есть внешний диск, отформатированный в NTFS. Вы создаёте там структуру папок и назначаете права – в эту папку можно участникам группы Administrators, в эту – обычным Users. Если вы перенесёте этот диск на другую систему, то все ACL’ы будут читаемы – потому что SID’ы что Administrators, что Users – одинаковы у любой NT-системы. Но если вы создадите свою собственную группу, то такого никогда не случится – её SID никогда не совпадёт с SID’ом группы на другой системе, потому что включает компонент S-1-5-21-уникальный идентификатор системы-RID. Поэтому если вы создадите у себя локальную группу Special Secret Administrators, а на соседней машине создадут Puny Faggots, то неприятной ситуации, когда добавляли права доступа для участников первой, а при переносе оказалось, что права доступа появились у второй, т.к. SID’ы совпали – вот такой ситуации не будет в принципе.
У пользователей, замечу, такого разделения нет – они всегда привязаны к идентификатору системы:
Что ж, с локальной системой всё ясно и несложно. Теперь – следующий шаг – появляется домен Windows NT.

Часть вторая – домен Windows NT – появление Domain Local и Security-групп

Работа с группами в одиночной системе – штука простая. Сложности появляются, когда надо создать свой authentication domain – т.е. подмножество систем, которые признавали бы не только свои локальные базы security principal’ов (хранящиеся в реестровой ветке HKLM\SAM\SAM), но и некую центральную и общую БД учётных записей.
Если вы берёте систему на базе Windows Server и делаете её контроллером домена – т.е. говорите, что теперь её хранилище security principal’ов будет общим, и ему будут доверять другие системы – она понимает возложенную ответственность и решается на апгрейд своего Security Accounts Manager’а. Ведь одно дело, когда предполагается использование базы только на одной системе – а другое дело, когда на нескольких. Плюс, домены могут доверять друг другу через систему domain trust’ов – а, следовательно, надо ещё и учитывать то, что должна обеспечиваться уникальность security principal’ов в пределах произвольного числа доменов.
Если просто взять и сделать общим SAM локальной машины – сразу появятся конфликты тех же builtin-групп; например, как при идентичных SID’ах группы BUILTIN\Adminstrators на всех системах сделать свой SAM доступным для остальных? Что будет обозначать запись в маркере доступа на произвольной, включённой в домен, машине “входит в группу с SID = S-1-5-32-544” – это значит, что участник локальных Administrators или общих-доменных Administrators? Как решать ситуации с “из соседнего домена придёт группа с таким же SID’ом”? Ситуация требовала и расширения функционала, и введения ограничений – и это произошло.
Было сделано следующее – существующая ситуация со встроенными и обычными группами была усложнена до “Есть два сту вида групп – локальные для этого домена (Domain Local) и глобальные с возможностью ‘выхода наружу’, за пределы домена (Global)”. У Domain Local при этом остаётся разделение на BUILTIN, т.е. встроенных и изначально существующих в домене, и обычных, созданных администраторами. Было два типа групп – стало два с половиной – локальные встроенные, локальные обычные, и глобальные.
Новый тип групп, Global, сразу же был ограничен до “в него могут входить только учётки”. Вложения однотипных групп (т.е. Global в Global) в домене Windows NT не было, поэтому всё, зачем нужны Global-группы – собрать в них ресурсы по какому-либо критерию (например, подразделение организации) и добавить эту группу в чей-нибудь ACL. Например, у папки, или у принтера. У любого объекта NT-системы, в общем. Простой пример – сделать группу BUH, добавить туда учётки всех сотрудников бухгалтерии и выдать этой группе права на папку Otchet2016 на файл-сервере.
Существующий подтип Builtin Local получил ограничение – в силу того, что SID’ы его участников не содержат доменный компонент, групп этого типа не видно при просмотре с рабочих станций и серверов домена. То есть, если в домене есть рабочая станция, и у неё есть своя локальная группа Administrators, то конфликт с имеющимися на контроллере домена BUILTIN\Administrators разрешается просто – что в локальную группу на этой рабочей станции, что в любой ACL на любом объекте на этой рабочей станции – добавить доменных BUILTIN\Administrators не выйдет, их просто не будет видно. Выборка по “потенциально возможным к добавлению” не покажет Builtin Local’ов. Они существуют только на системах, которые разделяют между собой “выросший” локальный SAM самого первого сервера, который стал контроллером этого домена – то есть, на контроллерах домена.
Domain Local же, как наследники “обычных локальных групп”, данного ограничения не имеют – их SID ведь содержит компонент с идентификатором домена – а, следовательно, уникальность в сравнении с локальными группами каждой входящей в домен системы поддерживается. Поэтому вы можете добавить, например, в локальную группу Administrators группу из домена, у которой будет тип Domain Local – никакого потенциального конфликта тут не будет. SID’ы этих групп, кстати, не поменялись при превращении сервера в первый контроллер домена в новом домене – поэтому если вы, например, создали локальную группу и выдали ей права на какой-то папке, то после DC promotion эта группа станет Domain Local и все её права сохранятся – ведь SID тот же.
В итоге ситуация стабильна – каждый домен обладает уникальным идентификатором, есть специальный тип групп, у которых в SID’е всегда этот уникальный идентификатор есть (Global). Назначение групп тоже понятно – в Global добавляем учётки с прицелом “им можно хоть где угодно права раздавать, хоть в другом домене”, Domain Local используем для групп-заглушек на ресурсах, вида “SRV1 Buh-Otchet2016 RO” (Read-Only на общей папке \\srv1\BUH\Otchet2016).
Но потребности растут – и ситуация изменяется ещё раз.

Лирическое отступление про максимальное количество групп и прочие технические мелочи

Возможность создавать много групп и делать сложные схемы вложения одних в другие, безусловно, технически ограничена. В части ограничения количества объектов типа “группа” в домене всё упрётся в размер хранилища NTDS в Active Directory, а также в максимально возможное количество RID’ов в данном домене. Оба этих барьера трудно достижимы – наштамповать миллиарды групп всё ж задачка не из бытовых. Но есть ограничение, которое достигнуть можно – это вопрос про “во сколько групп может входить пользователь”.
 
Ответ на этот вопрос, за время развития Active Directory, несколько раз изменялся – давайте разберёмся, почему и как.
 
Первичное техническое ограничение на количество групп, в которых одновременно может состоять конкретный пользователь, вызвано тем, что при логине с использованием протокола Kerberos (его поддержка появляется в Windows NT 5.0 и в Active Directory с момента её создания) будет необходимо передавать по сети сведения о членстве доменного пользователя в группах. Протокол Kerberos по умолчанию работает с использованием транспортного протокола UDP (впрочем, переключаем на TCP начиная с Windows 2000), и теоретически возможный размер Kerberos-данных – это максимальный размер UDP-датаграммы минус заголовок пакета Kerberos. Получается чуть меньше 64КБ (65.5 тысяч байт). Вычитаем минимальный размер маркера доступа (это 1200 байт – это минимум, размер может быть чуть больше, если будет, например, очень длинный FQDN или UPN/SPN). Получаем примерно 62КБ (где-то 63 тысячи байт). Учитываем, что при работе с веб-сервисами, тем же IIS, использующим при работе метод Negotiate, содержимое токена надо будет передавать по HTTP, в Base64 (т.е. упаковывать всё в 6ти битовые символы). В результате получим уменьшение технологически возможного размера до примерно 47КБ (около 48 тысяч байт). Это, повторюсь, техническое ограничение при условиях:
 
  • Наш Kerberos работает по UDP;
  • Мы используем Negotiate в IIS как метод авторизации доменных учётных записей;
  • Мы не тюнингуем Kerberos в плане доп.информации в заголовке и у нас учётка с нормальным именем (или хост с тривиальным по габаритам FQDN);
 
Поэтому операционная система, в частности встроенный в неё модуль поддержки Kerberos, имеет настройку, ограничивающую максимальный размер содержимого. Исторически этот размер, появившись в Windows 2000, был 8.000. В Windows 2000 Service Pack 2 он стал 12.000, а с Windows Server 2012 – 48.000. Вы можете его поправить, если что, простой настройкой параметра MaxTokenSize, который сейчас уже есть в стандартных групповых политиках (я предполагаю, что вы обновляете административные шаблоны у себя в домене):
Находится она, если что, в Computer Configuration \ Policies \ Administrative Templates \ System \ Kerberos, а называется Set maximum Kerberos SSPI context token buffer size. Учитывайте только, что это – именно максимальный размер самого содержимого токена, а не токена в смысле “весь керберосовский пакет”. Кстати, на KDC – т.е. на всех контроллерах – можно также выставить полезную настройку “журналировать события, когда токен не влез в указанные размеры”:
Находится она рядом с предыдущей в Computer Configuration \ Policies \ Administrative Templates \ System \ KDC, называется Warning for large Kerberos tickets.
 
Теперь добрались до связи всего этого с группами. Каждая запись о том, что данный security principal состоит в группе, занимает место. Больше всего места занимает запись о членстве в Domain Local-группе и в Universal-группе из чужого домена (об Universal чуть далее) – 40 байт. Запись о членстве в Global или Universal-группе своего домена занимает 8 байт. Используя эти данные, можно прикинуть, в каком количестве групп может состоять пользователь – это будет или 1200 Domain Local-групп, или 6000 Global-групп, или хз сколько Universal (зависит от того, из того же они домена, что и вы, или нет).
 
Но это будет ещё не очень точной прикидкой, потому что есть дополнительные факторы, влияющие на содержимое маркера доступа:
 
  • SID History – если учётная запись мигрировала из другого домена, и этот атрибут не пустой, а содержит SID’ы групп из предыдущего домена, то они тоже занимают место в маркере;
  • Delegation – если учётка trusted for delegation, то теоретический максимум можно делить пополам, т.к. в маркере будет 2 комплекта SID’ов;
 
Чтобы не замучаться поддерживать весь этот дремучий лес из различных ситуаций “много групп или не очень”, Microsoft выпустила статью про жёсткое ограничение количества групп до 1.015, и посоветовала не превышать число в 1.010 (хотя, как видно из вычислений, количество может быть в разы больше). Ситуация на некоторое время успокоилась – для спокойной работы можно выставить на уровне домена MaxTokenSize в 48.000 и не иметь никаких проблем (ещё лучше форсировать Kerberos на TCP-вариант, чтобы не натыкаться на ограничения размера UDP-датаграммы).
 
Помимо этого, в случае проблем с работой веб-сервисов, возможно, понадобится увеличить максимальный размер одиночного поля в HTTP-заголовке и одиночного запроса. По умолчанию они оба 16K, имеет смысл увеличить их хотя бы до 64К – это решит проблемы с ситуацией “большой маркер доступа и сбой 401.1 при авторизации на IIS” и в подобных: