Скелет начинает обрастать мясом. Одной из важных частей будущего FreeIPA v3.0 является возможность настраивать доверительные отношения с доменами Active Directory. Все это для того, чтобы пользователи FreeIPA и пользователи AD считались в обеих системам доверенными и не надо было их между собой синхронизировать. Теоретически, для того, чтобы это все работало, необходимо "лишь" использовать Kerberos. Проблема в том, что AD считает необходимым атрибутом доверительных отношений ответы по тем протоколам, которые она использует для своей внутренней деятельности. То есть, в первую очередь CLDAP и CIFS, причем так, что контекстуально информация, переданная по одному каналу (например, Kerberos протокол) должна быть понятна и в рамках запросов, использующих другие протоколы (CLDAP, LSA RPC). Это означает, что сервер Kerberos и другие службы как бы работают под одним крылом.
Для решения этой проблемы в Samba4 уже давно реализуются свой LDAP-сервер (и CLDAP в нем) и свой встроенный Kerberos-сервер (на основе Heimdal). Для того, чтобы внешние реализации LDAP и Kerberos могли бы обеспечить аналогичную функциональность, необходимо научить Samba отдавать некоторые операции наружу. В CIFS для этого теоретически существует end-point mapper, аналогичный RPC map для Sun RPC. То есть, один порт слушается smbd, а затем приходящие запросы раскидываются на обработчиков в отдельных процессах. На реализацию работающего диспетчера внешних обработчиков ушло несколько лет в Samba3, этот код стал стабильным относительно недавно.
Для того, чтобы установить доверительное отношение между двумя доменами достаточно не так и много вызовов. Создается пароль для доверительного отношения и, используя необходимые административные привилегии, отправляются два запроса LSA RPC CreateTrustedDomainEx2 -- к нашему серверу домена и к сервер доверяемого домена. Фактически, из основных требований здесь только административный доступ к чужому домену. В Samba3 в утилите net есть специальный раздел 'net rpc trust', который позволяет установить это самое доверие вручную. Утилита предполагает, что она запущена на своем же сервере с правами привилегированного пользователя, поскольку при работе ей требуется запись в некоторые базы данных Samba3, права на запись в которые выданы только руту, а открывает эти базы она самостоятельно.
В случае FreeIPA сам сервер FreeIPA, который занимается настройкой остальных сущностей, запущен как WSGI процесс, работающий под непривилегированным пользователем. При обращении к нему по XML-RPC или JSON со стороны клиента происходит делегирование имеющегося пользовательского билета Kerberos, на основании которого сервер FreeIPA и обращается к различным службам от имени этого пользователя. Службы в этом случае должны понимать авторизацию силами Kerberos, но сами по себе они работают тоже под непривилегированными пользователями, отличными от того, под которым работает WSGI процесс. Коммуникация между процессами идет средствами Unix domain sockets. То есть, использовать net rpc trust для установления доверительного отношения не получится, поскольку утилита net, запущенная из под пользователя apache, не сможет открыть напрямую соответствующую привилегированную базу, права на доступ к которой есть только у root. Впрочем, если бы они были у кого-то другого, это тоже было бы невозможно без принудительной выдачи прав на запись пользователю apache, что ломает всю стройную картину разделения прав.
У Samba4 есть автоматически генерируемые питоновые модули для довольно большой часть внутренних библиотек. Эти модули позволяют реализовать практически весь функционал 'net rpc trust' самостоятельно, обращаясь из кода на Питоне, запущенного под каким угодно пользователем, к соответствующим CIFS серверам, в том числе и локальному, работающему на том же сервере, что и FreeIPA. Беда только в том, что все эти модули не имеют нормальной документации и довольно неустойчивы к некорректным данным.
Это было введение. После некоторого количества итераций и патчей, как к FreeIPA, так и к Samba, удалось, наконец, реализовать подход, при котором все операции по установлению доверительных отношений выполняются из-под непривилегированного пользователя с применением делегированного билета администратора. Вот как выглядит простой запрос информации о домене (LSA RPC OpenInfoPolicy2), необходимый для определения параметров для заполнения запросов на установление доверительных отношений:
# ipa trust-fetch
----------------------------------------------------------------------------------------------------------------------------------------------
name: IPA
DNS domain: ipa.local
DNS forest: ipa.local
GUID: 00000015-35af-38a7-5973-0197a678d0ac
SID: S-1-5-21-950482351-2533454681-2899343526
----------------------------------------------------------------------------------------------------------------------------------------------
В логе Апача в это время (я использую уровень error для отладки):
[Mon Feb 13 12:50:03 2012] [notice] Apache/2.2.21 (Unix) DAV/2 mod_auth_kerb/5.4 mod_nss/2.2.17 NSS/3.12.9.0 mod_wsgi/3.3 Python/2.7.2 configured --
resuming normal operations
[Mon Feb 13 12:50:09 2012] [error] ipa: INFO: *** PROCESS START ***
[Mon Feb 13 12:50:09 2012] [error] ipa: INFO: *** PROCESS START ***
INFO: Current debug levels:
all: 10
tdb: 10
printdrivers: 10
lanman: 10
smb: 10
rpc_parse: 10
rpc_srv: 10
rpc_cli: 10
passdb: 10
sam: 10
auth: 10
winbind: 10
vfs: 10
idmap: 10
quota: 10
acls: 10
locking: 10
msdfs: 10
dmapi: 10
registry: 10
GENSEC backend 'gssapi_spnego' registered
GENSEC backend 'gssapi_krb5' registered
GENSEC backend 'gssapi_krb5_sasl' registered
GENSEC backend 'sasl-DIGEST-MD5' registered
GENSEC backend 'schannel' registered
GENSEC backend 'ntlmssp' registered
GENSEC backend 'spnego' registered
GENSEC backend 'krb5' registered
GENSEC backend 'fake_gssapi_krb5' registered
Using binding ncacn_np:master.ipa.local[,]
Mapped to DCERPC endpoint \pipe\lsarpc
added interface eth0 ip=192.168.111.137 bcast=192.168.111.255 netmask=255.255.255.0
added interface eth0 ip=192.168.111.137 bcast=192.168.111.255 netmask=255.255.255.0
Socket options:
SO_KEEPALIVE = 0
SO_REUSEADDR = 0
SO_BROADCAST = 0
TCP_NODELAY = 1
TCP_KEEPCNT = 9
TCP_KEEPIDLE = 7200
TCP_KEEPINTVL = 75
IPTOS_LOWDELAY = 0
IPTOS_THROUGHPUT = 0
SO_SNDBUF = 173080
SO_RCVBUF = 87380
SO_SNDLOWAT = 1
SO_RCVLOWAT = 1
SO_SNDTIMEO = 0
SO_RCVTIMEO = 0
TCP_QUICKACK = 1
TCP_DEFER_ACCEPT = 0
Starting GENSEC mechanism spnego
Starting GENSEC submechanism gssapi_krb5
Ticket in credentials cache for admin@IPA.LOCAL will expire in 0 secs
Received smb_krb5 packet of length 1186
Received smb_krb5 packet of length 1176
gensec_gssapi: credentials were delegated
GSSAPI Connection will have no cryptographic protection
Got KRB5 session key of length 32 (done)
num_setup=2, max_setup=0, param_total=0, this_param=0, max_param=0, data_total=72, this_data=72, max_data=65535, param_offset=84, param_pad=2, param_disp=0, data_offset=84, data_pad=0, data_disp=0
rpc request data:
[0000] 00 00 02 00 01 00 00 00 00 00 00 00 01 00 00 00 ........ ........
[0010] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
[0020] 00 00 00 00 00 00 00 00 04 00 02 00 00 00 00 00 ........ ........
[0030] 00 00 00 00 29 00 00 00 ....)...
num_setup=2, max_setup=0, param_total=0, this_param=0, max_param=0, data_total=80, this_data=80, max_data=4280, param_offset=84, param_pad=2, param_disp=0, data_offset=84, data_pad=0, data_disp=0
rpc reply data:
[0000] 00 00 00 00 13 00 00 00 00 00 00 00 38 4F E1 EA ........ ....8O..
[0010] 4C 71 00 00 00 00 00 00 Lq......
rpc request data:
[0000] 00 00 00 00 13 00 00 00 00 00 00 00 38 4F E1 EA ........ ....8O..
[0010] 4C 71 00 00 0C 00 Lq....
num_setup=2, max_setup=0, param_total=0, this_param=0, max_param=0, data_total=46, this_data=46, max_data=4280, param_offset=84, param_pad=2, param_disp=0, data_offset=84, data_pad=0, data_disp=0
rpc reply data:
[0000] 00 00 02 00 0C 00 00 00 06 00 08 00 04 00 02 00 ........ ........
[0010] 12 00 14 00 08 00 02 00 12 00 14 00 0C 00 02 00 ........ ........
[0020] 15 00 00 00 AF 35 A7 38 59 73 01 97 A6 78 D0 AC .....5.8 Ys...x..
[0030] 10 00 02 00 04 00 00 00 00 00 00 00 03 00 00 00 ........ ........
[0040] 49 00 50 00 41 00 00 00 0A 00 00 00 00 00 00 00 I.P.A... ........
[0050] 09 00 00 00 69 00 70 00 61 00 2E 00 6C 00 6F 00 ....i.p. a...l.o.
[0060] 63 00 61 00 6C 00 00 00 0A 00 00 00 00 00 00 00 c.a.l... ........
[0070] 09 00 00 00 69 00 70 00 61 00 2E 00 6C 00 6F 00 ....i.p. a...l.o.
[0080] 63 00 61 00 6C 00 00 00 04 00 00 00 01 04 00 00 c.a.l... ........
[0090] 00 00 00 05 15 00 00 00 AF 35 A7 38 59 73 01 97 ........ .5.8Ys..
[00A0] A6 78 D0 AC 00 00 00 00 .x......
[Mon Feb 13 12:50:09 2012] [error] ipa: INFO: admin@IPA.LOCAL: trust_fetch(): SUCCESS
Выделенные места показывают, что авторизация относительно сервера Samba произведена на основе билета Kerberos, который был делегирован командой ipa посредством XML-RPC. Саму команду я выполнял под рутом, что не принципиально -- она могла быть выполнена и на другой машине, и под непривилегированным пользователем. Для обращения к серверу AD придется передавать пароль и имя пользователя с правами администратора, поскольку у нас нет еще билета из домена Kerberos от AD. Теоретически, можно было бы получить оба билета, но такое делегирование полномочий подразумевает использование MIT KRB5 1.10 с некоторыми дополнительными патчами. Альтернативой может быть запрос к администратору AD с тем, чтобы он настроил свою часть доверенности самостоятельно (это требует пары кликов в соответствующем диалоге в Windows) и сообщил нам общий пароль на доверие, который и будет использован при установлении доверенности с нашей стороны. Эта альтернатива будет тоже доступна в финальной FreeIPA v3.0.
Осталось дописать вызовы для установления доверительных отношений в код модуля FreeIPA и большая часть функционала для FreeIPA v3.0 будет реализована.