W poprzednim artykule mogliśmy się zapoznać z zarządzaniem użytkownikami, którego zdecydowanymi zaletami są prostota i przejrzystość. Przez wiele lat uwierzytelnianie i zarządzanie hasłami było bezpośrednio oparte na umówionych plikach passwd, shadow i group, z czasem jednak ujawniły się ograniczenia tego rozwiązania i firma SunSoft opracowała nowy, kompatybilny z dotychczasowym, system uwierzytelnienia pod nazwą Linux-PAM, czyli Pluggable Authentication Modules for Linux. Żeby być precyzyjnym, firma SunSoft opracowała PAM dla systemu Solaris, późniejsza adaptacja dla systemu Linux to Linux-PAM. Oczywiście nadal możemy zarządzać użytkownikami w dotychczasowy, prosty sposób, jednak warto poznać, jak Linux-PAM działa i jakie daje nam możliwości.
Dlaczego w ogóle pojawiło się coś takiego jak Linux-PAM? Model tradycyjny zakładał, że każda aplikacja, która potrzebuje uwierzytelnić użytkownika, robi to sama. Z czasem, gdy tych aplikacji (głównie usług, jak np. ftp czy ssh) pojawiło się więcej oraz pojawiło się więcej sposobów uwierzytelnienia (np. login i hasło, certyfikaty, karty inteligentne), pojawiły się problemy.
Naturalne było utworzenie architektury, która poprzez oddzielenie procesu uwierzytelnienia od programów, które chcą go przeprowadzić, rozwiązałaby powyższe dwa problemy. Linux-PAM jest właśnie takim rozwiązaniem.
Głównym celem Linux-PAM jest dostarczenie bibliotek pozwalających na uwierzytelnienie użytkownika programom (usługom), które tego potrzebują. Wynikają z tego co najmniej dwie korzyści. Jedna to taka, że programy nie muszą implementować uwierzytelnienia samodzielnie, a druga, wynikająca z pierwszej, że jeśli rozszerzymy Linux-PAM o nowy sposób uwierzytelnienia, programów nie trzeba zmieniać (w szczególności nie trzeba ich rekompilować).
Najprościej schemat PAM można przedstawić następująco:
Linux-PAM zajmuje się 4 rodzajami zadań.
Do realizacji tych zadań są odpowiednie moduły, które również dzielimy na 4 odpowiadające grupy (listę wybranych modułów obejrzymy później).
Konfiguracja znajduje się w pliku /etc/pam.d/nazwa_programu (np. dla passwd jest to plik /etc/pam.d/passwd). Dodatkowo mamy plik /etc/pam.d/other zawierający domyślną konfiguracją dla programów, które takowej nie posiadają. Niezależnie mamy także konfigurację konkretnych modułów i odpowiednie pliki znajdują się w katalogu /etc/security/. Warto w tym miejscu zauważyć, że każdy plik w katalogu /etc/pam.d/ zawiera pewną liczbę wierszy, z których każdy odpowiada pewnej "akcji" uwierzytelnienia realizowanej przez wybrany moduł i określonej przez konfigurację zawartą w tym wierszu. Proces uwierzytelnienia można streścić następującą ilustracją:
Aplikacja X jest nieświadoma mechanizmów uwierzytelnienia, ale przygotowana do korzystania z Linux-PAM. Proces uwierzytelnienia przebiega następująco:
Konfiguracja pojedynczego wiersza z pliku z katalogu /etc/pam.d ma postać:
module-type control-flag module-path arguments
Znaczenie kolejnych pól jest następujące.
[wartosc1=dzialanie1 wartosc2=dzialanie2 ...]gdzie przykładowe wartości to user unknown, acct expired czy try again, a działania to ignore, ok, done, bad, die, reset. W praktyce jednak stosuje się uproszczony sposób określania tego parametru i polega na podaniu jednej z następujących wartości:
#%PAM-1.0 auth required pam_securetty.so auth include common-auth auth required pam_nologin.so account include common-account password include common-password session include common-session session required pam_lastlog.so nowtmp session required pam_resmgr.so session optional pam_mail.so standardPlik /etc/pam.d/common-auth
auth required pam_env.so auth required pam_unix2.soPlik /etc/pam.d/common-account
account required pam_unix2.soPlik /etc/pam.d/common-password
password required pam_pwcheck.so nullok password required pam_unix2.so nullok use_first_pass use_authtokPlik /etc/pam.d/common-session
session required pam_limits.so session required pam_unix2.so
Poznaliśmy trochę teorii jak to działa. Teraz zobaczymy jak można wiedzę o Linux-PAM wykorzystać w praktyce.
Przykład 1. Blokowanie dostępu do systemu przez utworzenie pliku /etc/nologin. Przed rozpoczęciem tworzymy użytkownika gucio.
# init 3a następnie po kilku chwilach wprowadzamy kombinację (Alt+F2)
# echo "Zalogowanie zablokowane" > /etc/nologin
# tail /var/log/messagesi patrzymy, że pojawił się wpis FAILED LOGIN
# mcedit /etc/pam.d/login
#auth required pam_nologin.so
auth required pam_nologin.so
# rm /etc/nologini teraz z powrotem wszyscy mogą się już normalnie logować.
Przykład 2. Ustawianie zasad dla nowych haseł.
# init 3a następnie po kilku chwilach wprowadzamy kombinację (Alt+F2)
# mcedit /etc/security/pam_pwcheck.confDomyślnie zawartość tego pliku wygląda następująco:
password: remember=13 cracklib nullokŁatwo się domyślić znaczenia poszczególnych opcji (remember pamięta historię haseł, cracklib wymusza skomplikowane hasła, a nullok dopuszcza hasła puste). W dalszej politykę trywialnych haseł z krótką historią. Dodatkowo wykorzystamy opcje: minlen=X, no_obscure_checks, tries=X. Wyjaśnienia wymaga tylko no_obscure_checks: ta opcja wyłącza proste testy dla haseł, czyli np. możemy wtedy zmienić hasło na 123456 (oczywiście w produkcyjnych rozwiązaniach nie należy używać tej opcji). Warto zauważyć, że jest również dualna opcja maxlen, ale w przypadku użycia md5 lub blowfish, jest ona ignorowana.
password: no_obscure_checks remember=5 minlen=3 tries=20
$ passwdPodajemy biężace hasło, a następnie wprowadzamy kolejno:
12 123Dalej zmieniamy hasło na
1234
# cat /etc/security/opasswdZauważamy, że mamy co najmniej 2 szyfrogramy rozdzielone przecinkami – jest to historia haseł użytkownika gucio.
12345 123456 1234567 12345678Na końcu spróbujmy zmienić wprowadzając jako nowe
123456 123Zmiana na 123 się nie uda, ponieważ mamy historię 5 haseł. Uda się zmiana na 123.
# cat /etc/security/opasswdTeraz powinno być rozdzielonych przecinkami 5 haseł. Za pomocą mcedit przywracamy też oryginalną zawartość pliku /etc/security/pam_pwcheck.conf, która powinna być następująca:
password: remember=13 cracklib nullok
# man pam_pwcheck
Przykład 3. Blokowanie dostępu do SSH.
# init 3a następnie po kilku chwilach wprowadzamy kombinację (Alt+F2)
account required pam_listfile.so item=user sense=deny file=/etc/ssh/sshd.deny onerr=succeeda następnie tworzymy plik /etc/ssh/sshd.deny i w kolejnych wiersza wprowadzamy nazwy użytkowników, dla których ssh ma być niedostępne, np.
gucio zenonNo i sprawdzamy, że poleceniem
$ ssh gucio@komputerobywatel gucio już się nie zaloguje. Łatwo też sprawdzić, że blokada działa również dla utwierzytelnienia opartego o klucze.
account required pam_listfile.so item=user sense=allow file=/etc/ssh/sshd.allow onerr=faila następnie tworzymy plik /etc/ssh/sshd.allow z listę użytkowników, którzy mają dostęp. Zachęcam potestować.