Konta z jednego miejsca: LDAP i Active Directory
Po tej lekcji: kursant rozumie, czym jest katalog LDAP i Active Directory, przeszukuje go ldapsearch, wie, jak /etc/nsswitch.conf i SSSD sprawiają, że konta z katalogu działają jak lokalne, konfiguruje sssd.conf, dołącza serwer do domeny przez realm discover i realm join, ustawia profil przez authselect i włącza automatyczne zakładanie folderów domowych.
Wstęp
Firma ma pięćdziesiąt serwerów. Przychodzi Ania. Admin loguje się na każdy i robi useradd. Pięćdziesiąt razy. Za rok Ania odchodzi i trzeba ją usunąć z pięćdziesięciu maszyn. Admin zapomina o trzech. Za dwa lata audytor pyta, czemu była pracownica ma aktywne konto na serwerze z danymi klientów.
Dlatego w firmach konta trzyma się w jednym miejscu. Jedno konto Ani, jedno hasło, wszędzie działa. Wyłączasz ją w jednym miejscu, znika ze wszystkich serwerów naraz. Dziś podłączamy do tego Linuksa.
Katalog, czyli centralna kadrowa
Pamiętasz księgę meldunkową /etc/passwd z lekcji 78? Każdy serwer ma własną. To jak firma, w której każde piętro prowadzi swoją listę pracowników. Katalog to jedna centralna kadrowa dla całej firmy. Wszystkie piętra dzwonią tam i pytają: „czy Jan Kowalski u nas pracuje, jaki ma numer i do których działów należy?”
LDAP, czyli Lightweight Directory Access Protocol, to język tych telefonów. Sposób zadawania pytań katalogowi. Najpopularniejsze serwery mówiące po LDAP to OpenLDAP, 389 Directory Server, a w firmach z Windowsami przede wszystkim Active Directory Microsoftu. AD to katalog LDAP, do tego Kerberos do sprawdzania haseł i DNS, żeby się wzajemnie znajdować. W świecie Red Hata jest jeszcze FreeIPA, czyli Red Hat Identity Management, ale zasada jest ta sama.
Dane w katalogu układają się w drzewo, jak adres pocztowy czytany od końca:
uid=jkowalski,ou=ludzie,dc=firma,dc=lanCzytaj od prawej: domena firma.lan (dc to domain component), w niej dział ludzie (ou to organizational unit), w nim Jan, którego login (uid) to jkowalski. Taki pełny adres to DN, distinguished name. Polska, Kraków, ulica, numer mieszkania.
Zaglądamy do katalogu: ldapsearch
Na potrzeby lekcji postawiłem na maszynie testowej mały serwer OpenLDAP na porcie 3890 i wrzuciłem do niego Jana Kowalskiego i grupę admini. Klient to pakiet [Ubuntu] ldap-utils, [RHEL] openldap-clients.
ldapsearch -x -H ldap://127.0.0.1:3890 -b dc=firma,dc=lan "(uid=jkowalski)" cn uidNumber homeDirectory loginShell# jkowalski, ludzie, firma.lan
dn: uid=jkowalski,ou=ludzie,dc=firma,dc=lan
cn: Jan Kowalski
uidNumber: 10001
homeDirectory: /home/jkowalski
loginShell: /bin/bash
# search result
search: 2
result: 0 Success
# numEntries: 1-x to proste logowanie zamiast Kerberosa. -H to adres serwera. -b to „base”, od którego miejsca drzewa szukać. W nawiasie filtr: szukam wpisu, którego uid to jkowalski. Na końcu lista pól, które chcę zobaczyć. Bez niej dostaniesz wszystko.
Znajome? uidNumber, homeDirectory, loginShell. To dokładnie te same pola co w /etc/passwd, tylko z nazwami zamiast pozycji między dwukropkami. Katalog jest księgą meldunkową na sterydach.
Grupy:
ldapsearch -x -LLL -H ldap://127.0.0.1:3890 -b dc=firma,dc=lan "(objectClass=posixGroup)" cn memberUiddn: cn=admini,ou=grupy,dc=firma,dc=lan
cn: admini
memberUid: jkowalski-LLL wycina komentarze. Czysty wynik do skryptów.
Sprawdzenie hasła, czyli „bind”, zalogowanie się do katalogu jako Jan:
ldapwhoami -x -H ldap://127.0.0.1:3890 -D uid=jkowalski,ou=ludzie,dc=firma,dc=lan -Wdn:uid=jkowalski,ou=ludzie,dc=firma,dc=lanZe złym hasłem:
ldap_bind: Invalid credentials (49)-W pyta o hasło, zamiast brać je z linii poleceń, gdzie zostałoby w historii. W Active Directory pytasz tak samo, tylko login wygląda jak jan@firma.lan, a drzewo jak dc=firma,dc=lan z działami w stylu ou=Users.
Recepcjonistka z listą: /etc/nsswitch.conf
Mamy katalog. Ale ls, id czy sshd nie umieją mówić po LDAP. One wołają bibliotekę systemową: „podaj mi użytkownika o numerze 10001”. A biblioteka sprawdza w /etc/nsswitch.conf, gdzie szukać. To recepcjonistka z kartką: „najpierw szukaj w segregatorze na biurku, potem zadzwoń do centrali”.
Przed podłączeniem katalogu:
passwd: files
group: files
shadow: filesPo zainstalowaniu na Ubuntu pakietu libnss-sss:
passwd: files sss
group: files sss
shadow: files sssfiles to segregator, czyli /etc/passwd. sss to telefon do SSSD, o którym za chwilę. Kolejność ma znaczenie: lokalne konta wygrywają. Dlatego lokalny root zawsze działa, nawet gdy katalog leży.
[Ubuntu] Pakiet dopisał sss sam. [RHEL] Tego pliku nie edytujesz ręcznie, robi to authselect.
Efekt:
getent passwd jkowalski
id jkowalski
grep jkowalski /etc/passwd; echo "grep: $?"jkowalski:*:10001:10000:Jan Kowalski:/home/jkowalski:/bin/bash
uid=10001(jkowalski) gid=10000(admini) groups=10000(admini)
grep: 1Jan istnieje dla systemu, ma numer, grupę, folder i powłokę, a w /etc/passwd go nie ma. Teraz widzisz, czemu w lekcji 78 męczyłem Cię getent zamiast grep. grep przeszukuje segregator. getent pyta recepcjonistkę, a ona dzwoni, gdzie trzeba.
SSSD: sekretarka z notesem
Każdy program mógłby dzwonić do katalogu sam. Ale wtedy każde ls -l to kilkaset zapytań przez sieć, a jak sieć padnie, nikt się nie zaloguje. Potrzebny jest pośrednik.
SSSD, System Security Services Daemon, to sekretarka, która rozmawia z centralą w imieniu całego piętra. I ma notes. Raz zapytała o Jana, zapisała odpowiedź i przez jakiś czas nie dzwoni ponownie. A jak centrala nie odbiera, zagląda do notesu.
Konfiguracja to /etc/sssd/sssd.conf. Wersja dla zwykłego LDAP:
[sssd]
services = nss, pam
domains = firma.lan
[domain/firma.lan]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://127.0.0.1:3890
ldap_search_base = dc=firma,dc=lan
cache_credentials = trueservices to okienka, które sekretarka obsługuje: nss odpowiada na pytania „kto to jest”, pam na pytania „czy hasło się zgadza”. id_provider mówi, skąd brać dane o kontach, auth_provider, kto sprawdza hasła. cache_credentials pozwala zalogować się z zapamiętanym hasłem, kiedy katalog jest nieosiągalny.
Pakiety: [Ubuntu] sssd-ldap sssd-tools libnss-sss libpam-sss, [RHEL] sssd sssd-ldap, a do Active Directory sssd-ad. Potem sudo systemctl enable --now sssd.
Narzędzia diagnostyczne:
sudo sssctl domain-status firma.lanOnline status: Online
Active servers:
LDAP: 127.0.0.1sudo sssctl user-checks jkowalskipam_acct_mgmt: Success
...
SSSD nss user lookup result:
- user name: jkowalski
- user id: 10001
- group id: 10000
- home directory: /home/jkowalski
- shell: /bin/bashA teraz test notesu. Wyłączam serwer LDAP:
sudo sssctl domain-status firma.lan -o
getent passwd jkowalskiOnline status: Offline
jkowalski:*:10001:10000:Jan Kowalski:/home/jkowalski:/bin/bashCentrala nie odbiera, a Jan dalej istnieje. Przez PAM zalogował się nawet zapamiętanym hasłem. Laptop w pociągu bez sieci, a Ty logujesz się kontem firmowym. To właśnie dzięki temu.
Notes ma też wadę: dopisałeś Jana w katalogu do nowej grupy, a serwer dalej pokazuje starą listę. Wtedy:
sudo sss_cache -EUnieważnia cały notes. Następne pytanie pójdzie do centrali.
Folder domowy przy pierwszym logowaniu
Jan ma w katalogu wpisany folder /home/jkowalski. Ale na tym serwerze nikt go nie założył. Pięćdziesiąt serwerów, pięćdziesiąt folderów do założenia ręcznie? Nie. Moduł PAM pam_mkhomedir tworzy go przy pierwszym logowaniu, z wyprawką z /etc/skel, którą znasz.
ls -d /home/jkowalski
echo 'haslo-jana' | sudo pamtester proba-ldap jkowalski authenticate acct_mgmt open_session
ls -la /home/jkowalskils: cannot access '/home/jkowalski': No such file or directory
pamtester: successfully authenticated
pamtester: account management done.
Creating directory '/home/jkowalski'.
pamtester: successfully opened a session
drwx------ 2 jkowalski admini 4096 Nov 3 16:33 .
-rw------- 1 jkowalski admini 220 Nov 3 16:33 .bash_logout
-rw------- 1 jkowalski admini 3771 Nov 3 16:33 .bashrc
-rw------- 1 jkowalski admini 807 Nov 3 16:33 .profileproba-ldap to znowu moja testowa usługa PAM, żeby nie psuć prawdziwego logowania. Hasło z katalogu, sesja otwarta, folder założony.
Na prawdziwym serwerze włączasz to tak:
sudo pam-auth-update --enable mkhomedir # Ubuntu
sudo authselect enable-feature with-mkhomedir # RHEL
sudo systemctl enable --now oddjobd # RHEL[RHEL] Na RHEL folder zakłada mała usługa oddjobd z pakietu oddjob-mkhomedir, dlatego musi działać.
authselect: gotowe zestawy na RHEL
Na Ubuntu klocki PAM i NSS dokładają pakiety i pam-auth-update. Na RHEL rządzi authselect. To jak menu w restauracji: zamiast samemu składać danie z dwudziestu składników, wybierasz zestaw i dodatki.
authselect list
authselect currentZestawy, czyli profile, są trzy: local dla kont tylko lokalnych, domyślny, sssd dla kont z katalogu przez SSSD i winbind dla bezpośredniej integracji z AD przez Sambę. Dodatki to features: with-mkhomedir, with-faillock z lekcji 80, with-sudo do reguł sudo trzymanych w katalogu.
sudo authselect select sssd with-mkhomedir with-faillockTa jedna komenda przepisuje /etc/nsswitch.conf i pliki /etc/pam.d/system-auth oraz password-auth. A w tych plikach na górze stoi:
# Do not modify this file manually, use authselect instead. Any user changes will be overwritten.Traktuj to dosłownie. Ręczne poprawki znikną przy następnym authselect. Ten sam los spotyka ręczną poprawkę w /etc/nsswitch.conf.
Active Directory: realm
Ręczne pisanie sssd.conf dla AD jest długie: Kerberos, konto komputera w domenie, mapowanie identyfikatorów. Dlatego jest realm, z pakietu realmd. Ten robi to wszystko za Ciebie.
Pakiety: [Ubuntu] sssd-ad sssd-tools realmd adcli, [RHEL] realmd oddjob oddjob-mkhomedir sssd adcli krb5-workstation samba-common-tools.
Krok pierwszy: znaleźć domenę.
realm discover firma.lanU mnie, bez prawdziwego kontrolera domeny:
realm: No such realm found: firma.lanrealm szuka kontrolera przez DNS, w specjalnych rekordach SRV, które AD sam publikuje. Jeśli Twój serwer nie używa DNS-a domeny, nic nie znajdzie. To najczęstsza przyczyna kłopotów: najpierw DNS, potem domena.
Z prawdziwym AD dostaniesz między innymi:
ad1.example.com
type: kerberos
realm-name: AD1.EXAMPLE.COM
configured: no
server-software: active-directory
client-software: sssdconfigured: no, czyli jeszcze nie jesteśmy członkiem. Krok drugi:
sudo realm join -U administrator ad1.example.com-U to konto w AD, które może dołączać komputery do domeny. Pyta o jego hasło. Potem realm zakłada w AD konto komputera, zapisuje klucz Kerberosa tego serwera, pisze sssd.conf i podłącza SSSD do NSS i PAM. [RHEL] Również przez authselect. [Ubuntu] Nie włącza zakładania folderów, więc pam-auth-update --enable mkhomedir robisz sam.
Sprawdzenie:
realm list
id administrator@ad1.example.com
getent passwd jan@ad1.example.comZwróć uwagę na @domena w loginie. realm join ustawia use_fully_qualified_names = True, więc użytkownicy AD mają pełne nazwy, a foldery domyślnie trafiają do /home/login@domena. To chroni przed sytuacją, w której lokalny jan i domenowy jan to dwie różne osoby z tym samym loginem.
Krok trzeci, najważniejszy dla bezpieczeństwa: kto może się logować. Po join zwykle mogą wszyscy z domeny. Cała firma, z księgowością i stażystami, na serwerze z bazą danych. Zawężasz:
sudo realm deny --all
sudo realm permit -g admini-linux@ad1.example.comNajpierw nikt, potem tylko grupa. Zasada najmniejszych uprawnień z lekcji 79 w wersji dla całej firmy. A sudo dla adminów z domeny dajesz jak zwykle w /etc/sudoers.d, grupą: %admini-linux@ad1.example.com ALL=(ALL) ALL.
Jak to działa pod spodem
Wpisujesz id jkowalski. Program woła funkcję biblioteki C getpwnam(). Biblioteka czyta /etc/nsswitch.conf, widzi files sss, szuka w /etc/passwd, nie znajduje, ładuje moduł libnss_sss i przez gniazdo lokalne pyta proces sssd_nss. Ten zagląda do pamięci podręcznej w /var/lib/sss/db. Jeśli wpis jest świeży, odpowiada od razu. Jeśli nie, prosi proces sssd_be, czyli backend domeny, który pyta serwer LDAP albo AD przez sieć i odświeża notes.
Logowanie idzie drugą drogą: sshd pyta PAM, PAM w stosie auth trafia na pam_sss.so, ten pyta sssd_pam, a backend sprawdza hasło. W czystym LDAP przez bind, czyli to, co zrobił ldapwhoami. W AD przez Kerberosa.
Ciekawostka: lista wszystkich użytkowników z getent passwd nie pokazuje Jana. SSSD domyślnie nie wylicza całego katalogu, bo w firmie z dziesięcioma tysiącami ludzi każde takie pytanie pobierałoby wszystkich. Pyta się o konkretne osoby po nazwie albo numerze.
Ściąga flag
| Komenda | Flaga | Co robi |
|---|---|---|
ldapsearch | -x | proste logowanie (bez Kerberosa) |
ldapsearch | -H ldap://serwer | adres serwera (ldaps:// szyfrowany) |
ldapsearch | -b dc=firma,dc=lan | od którego miejsca drzewa szukać |
ldapsearch | -D dn -W | zaloguj się jako ten DN, zapytaj o hasło |
ldapsearch | -LLL | wynik bez komentarzy |
ldapwhoami | -x -D dn -W | sprawdza login i hasło w katalogu |
getent | passwd login | pyta przez NSS, także katalog |
sssctl | domain-status domena | czy SSSD widzi katalog |
sssctl | user-checks login | pełna diagnostyka użytkownika |
sssctl | config-check | sprawdza sssd.conf |
sss_cache | -E | unieważnia notes SSSD |
authselect | list / current | profile / aktualny profil (RHEL) |
authselect | select sssd with-mkhomedir | profil SSSD z folderami domowymi |
authselect | enable-feature with-… | włącza dodatek |
pam-auth-update | --enable mkhomedir | foldery domowe (Ubuntu) |
realm | discover domena | znajduje domenę przez DNS |
realm | join -U admin domena | dołącza serwer do domeny |
realm | list | do jakich domen należymy |
realm | deny --all / permit -g grupa | kto może się logować |
realm | leave | odłącza od domeny |
⚠ Typowy błąd
Piszesz sssd.conf w edytorze, zapisujesz, uruchamiasz. I nic:
sudo chmod 644 /etc/sssd/sssd.conf
sudo sssd -i[sssd] [sss_ini_read_sssd_conf] (0x0020): Permission check on config file failed.
[sssd] [confdb_init_db] (0x0020): Cannot convert INI to LDIF [1432158324]: [File ownership and permissions check failed]
[sssd] [main] (0x0010): SSSD couldn't load the configuration database [1432158324]: File ownership and permissions check failedSSSD odmawia startu, bo plik konfiguracyjny może przeczytać każdy. A w takim pliku często leży hasło konta, którym serwer łączy się z katalogiem. SSSD woli nie ruszyć, niż pracować z sejfem otwartym na korytarz. Dokumentacja Red Hata i Ubuntu mówi to samo: uprawnienia 0600, właściciel root:root.
sudo chown root:root /etc/sssd/sssd.conf
sudo chmod 600 /etc/sssd/sssd.conf
sudo sssctl config-check
sudo systemctl restart sssdNa systemie z systemd ten sam błąd zobaczysz w journalctl -u sssd. A sssctl config-check przy okazji wyłapie literówki w nazwach opcji, zanim SSSD w ogóle wstanie.
✎ Zadanie
Załóż użytkownika stazysta w grupie praktykanci, wymuś zmianę hasła przy pierwszym logowaniu i pozwól mu przez sudo tylko na restart jednej usługi. Sprawdź sudo -l -U stazysta i getent passwd stazysta.
Pokaż rozwiązanie
Stażysta, grupa, hasło do zmiany i sudo tylko na jedną rzecz. U mnie wyszło tak:
sudo groupadd praktykanci
sudo useradd -m -s /bin/bash -g praktykanci stazysta
sudo passwd stazysta # hasło startowe, podajesz je stażyście osobnym kanałem
sudo chage -d 0 stazysta # data ostatniej zmiany hasła = 1970, więc musi zmienić od razu
sudo visudo -f /etc/sudoers.d/stazystaW pliku jedna linijka:
stazysta ALL=(root) /usr/bin/systemctl restart nginx.serviceI sprawdzenie:
sudo chage -l stazysta | head -2
sudo -l -U stazysta
getent passwd stazystaLast password change : password must be changed
Password expires : password must be changed
User stazysta may run the following commands on vm:
(root) /usr/bin/systemctl restart nginx.service
stazysta:x:1001:1001::/home/stazysta:/bin/bashUID i GID wyszły 1001, bo to pierwsze konto i pierwsza grupa założone po moim. Jeśli masz już więcej kont, u Ciebie będzie wyższy numer. Ważne są trzy rzeczy: pełna ścieżka do systemctl, pełna nazwa usługi i visudo, a nie zwykły edytor. Bez pełnej ścieżki stażysta podłoży własny program o nazwie systemctl i dostanie roota. Bez visudo jedna literówka i nikt już nie dostanie roota, łącznie z Tobą. Stażysta może teraz zrestartować nginx o trzeciej w nocy. I nic więcej. Czyli dokładnie tyle, ile powinien móc stażysta o trzeciej w nocy.
Co dalej
Konta, grupy, sudo i katalog masz za sobą. W następnej lekcji drugi strażnik Linuksa, który pilnuje nawet roota: SELinux. Tryby, etykiety, restorecon, semanage i czytanie odmów bez strachu. I bez wyłączania go przy pierwszym problemie.