Левинца Егор
Обсуждение статьи на форуме проекта Pro-LDAP.ru.
Имеется настроенный домен Active Directory windom.net. Требуется настроить веб-сервер араche2 на сервере с Ubuntu так, чтобы он обслуживал два виртуальных хоста, — windom.net (он же www.windom.net) и sandbox.windom.net, — в которых пользователи проходили бы Kerberos-аутентификацию в Active Directory. Примерная DNS-зона:
windom.net A 10.10.0.3 # Корень домена, A-запись указывает на ip-адрес веб-сервера | |\ gate A 10.10.0.1 # Шлюз |\ ads A 10.10.0.2 # Контроллер домена на MS Windows 2003 R2 |\ webserver A 10.10.0.3 # Веб-сервер на Ubuntu 14.04, apache-2.4.7, mod_auth_kerb-5.4.1 |\ www CNAME webserver # Ссылка на webserver для VitrualHost apache2, общий портал \ sandbox CNAME webserver # Ссылка на webserver для VitrualHost apache2, ресурс для разработчиков
С одной стороны, подобная конфигурация уже много раз хорошо документирована в Интернет и нет смысла повторяться. С другой стороны, для работы mod_auth_kerb требуется keytab-файл с принципалами сервисов apache2. Сначала мне казалось, что там должны быть такие принципалы:
HTTP/windom.net@WINDOM.NET HTTP/www.windom.net@WINDOM.NET HTTP/sandbox.windom.net@WINDOM.NET HTTP/webserver.windom.net@WINDOM.NET
Но на самом деле, как выяснилось опытным путём, оказалось достаточно двух (что, в общем-то, логично, учитывая работу протокола HTTP):
HTTP/windom.net@WINDOM.NET HTTP/webserver.windom.net@WINDOM.NET
Кстати, это даёт некоторый бонус: виртуальные хосты, сколько бы их ни было, имена которых организуются CNAME-записями DNS, указывающими на основной веб-сервер, не нуждаются в дополнительных именах сервисных принципалов.
Итак, задача: сформировать в среде Active Directory рабочий keytab-файл с несколькими принципалами сервисов для его использования в apache2.
Что мы знаем о keytab-файлах? В Kerberos keytab (от "key table", "таблица ключей") — способ хранения долговременных ключей для одного или нескольких принципалов. Чаще всего таблицы ключей хранятся в виде файлов стандартизированного формата (те самые keytab-файлы). Таблица ключей может включать в себя одну или несколько записей, каждая из которых состоит из отметки времени (когда запись была добавлена в keytab), имени принципала, номера версии ключа (key version number или KVNO), типа шифрования и собственно зашифрованного ключа. Кроме всего прочего, этот ключ будет использоваться для аутентификации принципала в базе данных безопасности KDC. KVNO — целое положительное число, дополнительный критерий защиты: если в keytab несколько записей для одного и того же принципала с разным KVNO, валидной будет считаться та запись, KVNO которой совпадает с текущим KVNO этого принципала в базе данных безопасности KDC (обычно запись с наибольшим KVNO).
В среде Active Directory база данных безопасности KDC — это LDAP-каталог. Проверка валидности принципалов (пользователей и сервисов) происходит на основании паролей учётных записей пользователей или компьютеров, к которым "привязаны" эти принципалы. Имена принципалов пользователей хранятся в атрибуте userPrincipalName
, принципалов сервисов — в атрибуте servicePrincipalName
. У каждой учётной записи есть KVNO (хранится в атрибуте msDS-KeyVersionNumber
). При смене пароля учётной записи KVNO увеличивается на единицу и все keytab-записи с принципалом, привязанным к этой учётной записи, и меньшим KVNO становятся невалидными, даже если пароли совпадают.
Следовательно, нам нужно создать учётную запись в LDAP-каталоге Active Directory, установить ей пароль (известный нам), привязать к этой учётной записи необходимые имена принципалов сервисов и сформировать keytab-файл с этими принципалами и ключами, основанными на известном нам пароле учётной записи.
Остальная теория — по мере выполнения.
Первая дилемма, с которой сталкиваются администраторы — какую учётную запись заводить: пользователя или компьютера. Обычно заводят учётную запись пользователя на том основании, что там легко задаётся пароль. Мне это кажется не совсем верным, поскольку сервисы работают на компьютерах и логичнее завести для этих целей учётку компьютера. Тем более учётки компьютеров не устаревают никогда. Но если вы всё же решили использовать учётку пользователя, принципиального значения это не имеет, просто скорректируйте команду создания учётной записи под себя.
Второй вопрос при создании учётки компьютера — стоит ли использовать уже имеющуюся учётку, если Ваш сервер является членом домена? В моём случае на том же Ubuntu-сервере работает samba и учётная запись компьютера webserver создалась в Active Directory автоматически при вводе сервера в домен. Я считаю — не стоит, на том основании, что члены домена периодически (по умолчанию раз в 30 дней) меняют пароль своей учётной записи, поэтому keytab-файл (если он не связан с keytab-файлом samba) придётся переделывать. В общем, я решил завести новую учётную запись компьютера и назвать её www.
Наконец, как лучше создавать учётную запись компьютера: графическими средствами (ADUC) или из командной строки? Это дело вкуса. Единственный момент: при создании учётки из командной строки пароль ей не назначается и KVNO будет равен 1, а при создании из оснастки ADUC учётной записи сразу назначается некий "стандартный" пароль, и KVNO у неё будет 2. Это необходимо будет учитывать при выполнении последующих шагов.
Итак, создадим учётную запись компьютера www:
C:\Program Files\Support Tools>dsadd computer "CN=www,CN=Computers,DC=windom,DC=net" dsadd успешно:CN=www,CN=Computers,DC=windom,DC=net
Проверим интересующие нас атрибуты учётной записи:
C:\Program Files\Support Tools>ldifde -d "CN=www,CN=Computers,DC=windom,DC=net" -l "userPrincipalName,servicePrincipalName,msDS-KeyVersionNumber" -f c:\tmp\account.ldif ... C:\Program Files\Support Tools>type c:\tmp\account.ldif dn: CN=www,CN=Computers,DC=windom,DC=net changetype: add msDS-KeyVersionNumber: 1
Наша учётная запись создана без пароля (KVNO=1), имена принципалов пользователя и сервиса не назначены.
Если честно, этот шаг необязательный, поскольку применяемая на следующих двух шагах утилита ktpass так или иначе "привязывает" имя принципала сервиса к учётной записи. Но раз уж мы решили сделать всё правильно, то выполним привязку явно. Это делается с помощью утилиты setspn. Первые две команды назначают учётной записи компьютера требуемые нам имена принципалов сервиса, третья — выводит список назначенных учётной записи принципалов:
C:\Program Files\Support Tools>setspn -A HTTP/windom.net@WIMDOM.NET www Registering ServicePrincipalNames for CN=www,CN=Computers,DC=windom,DC=net HTTP/windom.net@WIMDOM.NET Updated object C:\Program Files\Support Tools>setspn -A HTTP/webserver.windom.net@WIMDOM.NET www Registering ServicePrincipalNames for CN=www,CN=Computers,DC=windom,DC=net HTTP/webserver.windom.net@WIMDOM.NET Updated object C:\Program Files\Support Tools>setspn -L www Registered ServicePrincipalNames for CN=www,CN=Computers,DC=windom,DC=net: HTTP/webserver.windom.net@WIMDOM.NET HTTP/windom.net@WIMDOM.NET
Проверим интересующие нас атрибуты учётной записи:
C:\Program Files\Support Tools>ldifde -d "CN=www,CN=Computers,DC=windom,DC=net" -l "userPrincipalName,servicePrincipalName,msDS-KeyVersionNumber" -f c:\tmp\account.ldif ... C:\Program Files\Support Tools>type c:\tmp\account.ldif dn: CN=www,CN=Computers,DC=windom,DC=net changetype: add servicePrincipalName: HTTP/webserver.windom.net@WIMDOM.NET servicePrincipalName: HTTP/windom.net@WIMDOM.NET msDS-KeyVersionNumber: 1
Пароля всё ещё нет (KVNO=1), имя принципала пользователя не назначено, но есть два имени принципалов сервиса.
Здесь в игру вступает супер-инструмент Microsoft: утилита ktpass. Она делает всё и сразу, поэтому пользоваться ей необходимо осторожно, иначе есть шанс всё испортить и придётся удалять учётку и начинать заново. Если Вы ещё не сталкивались с этой утилитой, лучше сразу посмотреть официальное руководство, чтобы представлять, о чём пойдёт речь далее.
Основной функционал ktpass:
Как видите, функционал богатый и чёткого описания как всё это должно работать, нет. Поэтому ещё раз предупреждаю: будьте внимательны и осторожны, перед выполнением команды Вы должны чётко понимать, что собираетесь сделать.
Стоит обратить внимание на то, как именно задаются аргументы при вызове ktpass. Некоторые из них могут задаваться с указанием знаков "-" или "/", например -out и /out — это одно и то же. Другие же аргументы задаются с указанием знаков "-" или "+", и это уже далеко не одно и то же. Например, -answer и +answer задают режим интерактивности работы утилиты: в первом случае при возникновении вопроса она будет ждать ответа от пользователя, во втором — самостоятельно положительно отвечать на возникающие вопросы. Чтобы не путаться, в примерах ниже "простые" аргументы я всегда указываю со знаком "/", а "альтернативные" — с требуемым по ситуации знаком.
Итак, нам нужно задать пароль учётной записи компьютера и сформировать keytab-файл для первого принципала сервиса. При этом (по умолчанию) имя принципала сервиса будет привязано к учётной записи, а также задано в качестве имени принципала пользователя этой учётной записи. Выполним команду:
C:\Program Files\Support Tools>ktpass /mapuser WINDOM\www$ /princ HTTP/windom.net@WIMDOM.NET /ptype KRB5_NT_SRV_HST /pass XXXXXXXXX /out c:\tmp\a1.keytab +answer Targeting domain controller: ADS.windom.net Using legacy password setting method Successfully mapped HTTP/windom.net to WWW$. WARNING: Account WWW$ is not a user account (uacflags=0x1021). WARNING: Resetting WWW$'s password may cause authentication problems if WWW$ is being used as a server. Reset WWW$'s password [y/n]? auto: YES Key created. Output keytab to c:\tmp\a1.keytab: Keytab version: 0x502 keysize 61 HTTP/windom.net@WIMDOM.NET ptype 3 (KRB5_NT_SRV_HST) vno 2 etype 0x17 (RC4-HMAC) keylength 16 (0xaa00bb11cc22dd33aa44bb55cc66dd77)
Подробнее остановимся на переданных аргументах. В аргументе /mapuser WINDOM\www$
указывается имя учётной записи, к которой будет привязываться принципал сервиса. В аргументе /princ HTTP/windom.net@WIMDOM.NET
указывается имя принципала сервиса, который мы собираемся привязывать, и для которого будет сформирована keytab-запись. В аргументе /ptype KRB5_NT_SRV_HST
указывается тип принципала. Я посчитал, что из возможных вариантов для учётки компьютера тип KRB5_NT_SRV_HST
наиболее уместен, к тому же ktpass не ругается на несоответствие типов принципала, как было в случае указания универсального и рекомендуемого типа KRB5_NT_PRINCIPAL
. В аргументе /pass
задаётся пароль сразу и для учётной записи компьютера, и для формирования ключа в keytab-записи с использованием нужного алгоритма шифрования. Кстати об алгоритмах шифрования: в MS Windows Server 2003 R2 их немного, поэтому я не стал задавать аргумент /crypto
, и ktpass выбрал единственно приемлемый вариант RC4-HMAC
(по умолчанию). В MS Windows Server 2008 R2 алгоритмов побольше, есть из чего выбрать, или вообще передать значение /crypto ALL
(в 2003-м сервере не поддерживается). Вернёмся к нашим паролям. Поскольку у нас два принципала сервиса в одной учётке, пароль для них нужно указывать один и тот же, поэтому использовать аргумент +rndpass
(генерация случайного пароля) нельзя. В аргументе /out c:\tmp\a1.keytab
указан keytab-файл (промежуточный), куда мы будем выводить информацию по keytab-записи первого принципала сервиса. Наконец, аргумент +answer
говорит о том, что на все возникающие вопросы нужно отвечать утвердительно.
Коротко о выводе команды. Сначала ktpass сообщил нам об успешной привязке принципала сервиса к учётной записи. Затем предупредил о том, что смена пароля учётной записи компьютера может привести к выбрасыванию компьютера из домена и попросил подтвердить это действие. Благодаря аргументу +answer
автоматически получил утвердительный ответ и (ВНИМАНИЕ!) поменял пароль учётной записи (в нашем случае — задал его). Затем он сформировал ключ принципала сервиса и вывел keytab-запись в указанный keytab-файл. Последняя строка вывода даёт нам представление о содержимом keytab-записи, оно соответствует переданным аргументам. Обратите внимание на подстроку vno 2
, она говорит о том, что в keytab-записи используется KVNO=2 (номер повысился при смене пароля учётной записи). Да, хотя явно об этом не говорится, было задано имя принципала пользователя учётной записи (совпадает с переданным именем принципала сервиса).
Проверим интересующие нас атрибуты учётной записи:
C:\Program Files\Support Tools>ldifde -d "CN=www,CN=Computers,DC=windom,DC=net" -l "userPrincipalName,servicePrincipalName,msDS-KeyVersionNumber" -f c:\tmp\account.ldif ... C:\Program Files\Support Tools>type c:\tmp\account.ldif dn: CN=www,CN=Computers,DC=windom,DC=net changetype: add userPrincipalName: HTTP/windom.net@WIMDOM.NET servicePrincipalName: HTTP/windom.net servicePrincipalName: HTTP/webserver.windom.net@WIMDOM.NET servicePrincipalName: HTTP/windom.net@WIMDOM.NET msDS-KeyVersionNumber: 2
Пароль установлен (KVNO=2), имя принципала пользователя назначено, добавлено ещё одно имя принципала сервиса.
На этом этапе нам нужно создать keytab-запись для второго принципала сервиса с ключом на основе того же пароля, импортировать keytab-запись первого принципала сервиса из промежуточного keytab-файла, созданного на предыдущем шаге, и записать обе keytab-записи в итоговый keytab-файл. При этом нам нельзя менять пароль самой учётной записи компьютера, поскольку KVNO этой учётки повысится и keytab-запись, созданная на предыдущем этапе, перестанет быть валидной. Выполним команду:
C:\Program Files\Support Tools>ktpass /mapuser WINDOM\www$ /princ HTTP/webserver.windom.net@WIMDOM.NET /ptype KRB5_NT_SRV_HST /pass XXXXXXXXX -setpass /kvno 2 /in c:\tmp\a1.keytab /out c:\tmp\apache2.keytab -setupn Existing keytab: Keytab version: 0x502 keysize 61 HTTP/windom.net@WIMDOM.NET ptype 3 (KRB5_NT_SRV_HST) vno 2 etype 0x17 (RC4-HMAC) keylength 16 (0xaa00bb11cc22dd33aa44bb55cc66dd77) Targeting domain controller: ADS.windom.net Using legacy password setting method Successfully mapped HTTP/webserver.windom.net to WWW$. Key created. Output keytab to c:\tmp\apache2.keytab: Keytab version: 0x502 keysize 61 HTTP/windom.net@WIMDOM.NET ptype 3 (KRB5_NT_SRV_HST) vno 2 etype 0x17 (RC4-HMAC) keylength 16 (0xaa00bb11cc22dd33aa44bb55cc66dd77) keysize 71 HTTP/webserver.windom.net@WIMDOM.NET ptype 3 (KRB5_NT_SRV_HST) vno 2 etype 0x17 (RC4-HMAC) keylength 16 (0xaa00bb11cc22dd33aa44bb55cc66dd77)
Аргументы /mapuser
, /princ
и /ptype
имеют тот же смысл, что и на предыдущем шаге. Пароль в аргументе /pass
, очевидно, должен совпадать с паролем учётной записи компьютера, поэтому мы задаём его таким же, как и на предыдущем шаге. Важнейший момент: чтобы не повышать KVNO, нам нельзя переназначать пароль самой учётной записи компьютера, за это отвечает аргумент -setpass
. Таким образом, пароль из аргумента /pass
будет использован только для создания keytab-записи. Из-за того, что пароль учётки не менялся, ktpass (по крайней мере в MS Windows Server 2003 R2) теряется — какой KVNO нужно назначить keytab-записи? Аргументом /kvno 2
мы явно указываем ему номер KVNO. В аргументе /in c:\tmp\a1.keytab
мы указываем файл, из которого необходимо импортировать уже имеющиеся keytab-записи (промежуточный keytab-файл, созданный на предыдущем шаге). В аргументе /out c:\tmp\apache2.keytab
указывается имя итогового keytab-файла, куда будут записаны импортированная и вновь сформированная keytab-записи. Наконец, аргументом -setupn
мы указываем, что переназначать имя принципала пользователя учётной записи компьютера не требуется.
Теперь рассмотрим вывод команды. Первым делом ktpass показал нам содержимое импортированной из промежуточного файла keytab-записи. Затем сообщил об успешной привязке принципала сервиса к учётной записи. Затем он сформировал ключ принципала сервиса и вывел две keytab-записи в указанный keytab-файл. Обратите внимание, что KVNO двух keytab-записей совпадает (vno 2
).
Проверим интересующие нас атрибуты учётной записи:
C:\Program Files\Support Tools>ldifde -d "CN=www,CN=Computers,DC=windom,DC=net" -l "userPrincipalName,servicePrincipalName,msDS-KeyVersionNumber" -f c:\tmp\account.ldif ... C:\Program Files\Support Tools>type c:\tmp\account.ldif dn: CN=www,CN=Computers,DC=windom,DC=net changetype: add userPrincipalName: HTTP/windom.net@WIMDOM.NET servicePrincipalName: HTTP/webserver.windom.net servicePrincipalName: HTTP/windom.net servicePrincipalName: HTTP/webserver.windom.net@WIMDOM.NET servicePrincipalName: HTTP/windom.net@WIMDOM.NET msDS-KeyVersionNumber: 2
Пароль учётной записи не изменился (KVNO=2), имя принципала пользователя не изменилось, добавлено ещё одно имя принципала сервиса.
Собственно всё, задача решена: правильный keytab-файл для двух принципалов сервиса сформирован. Осталось передать его в нужное место, ограничить права доступа и тестировать работу аутентификации apache2.
И ещё один небольшой бонус напоследок, пока мы не покинули Windows-сервер: утилита ktpass — это единственный известный мне инструмент, с помощью которого можно легально (не прибегая к ухищрениям c LDAP-каталогом) сменить пароль учётной записи компьютера. Для этого нужно просто "попытаться" привязать к ней неверно сформированное имя принципала сервиса. ktpass выдаст ошибку, но пароль всё равно сменит. Пример:
C:\Program Files\Support Tools>ktpass /mapuser WINDOM\somepc$ /princ imposible@WIMDOM.NET /pass XXXXXXXXX -setupn +answer Targeting domain controller: ADS.windom.net Using legacy password setting method Failed to set property "servicePrincipalName" to "imposible" on Dn "CN=somepc,CN=Computers,DC=windom,DC=net": 0x13. WARNING: Unable to set SPN mapping data. If SOMEPC$ already has SPN mapping installed for imposible, this is no cause for concern. WARNING: Account SOMEPC$ is not a user account (uacflags=0x1021). WARNING: Resetting SOMEPC$'s password may cause authentication problems if SOMEPC$ is being used as a server. Reset SOMEPC$'s password [y/n]? auto: YES WARNING: pType and account type do not match. This might cause problems. Key created.
Материалы, которые помогли мне разобраться в теме:
Последнее изменение страницы — 20 апреля 2016 года.
Обсуждение статьи на форуме проекта Pro-LDAP.ru.