Pokazywanie postów oznaczonych etykietą RH413. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą RH413. Pokaż wszystkie posty

Zabezpieczanie filesystemu przy użyciu opcji mountowania - mount i tune2fs

Red Hat 6.x / CentOS 6.x
Dzięki specjalnym opcjom mountowania możemy ograniczyć lub umożliwić pewne zachowania na systemie plików w naszym OS-ie. Część tych opcji, poza standardowym fstab-em może być zdefiniowana w metadanych naszego filesystemu.

Opcje fstab / mount

Podczas mountowania filesystemu możemy wymusić na nim pewne zachowania. Zachowania te definiujemy przez podanie odpowiednich opcji mountowania (zarówno w komendzie mount jak i pliku fstab).

Przytoczmy zatem przykładowy wpis fstaba

/dev/mapper/vg_centos-lv_root /                       ext4    defaults        1 1

 * W pierwszej kolumnie umieszczony jest wskaźnik urządzenia, które chcemy zamountować - w naszym przykładzie to dysk /dev/mapper/vg_centos-lv_root.
* Druga kolumna to punkt mountowania w systemie - tutaj będzie to katalog /.
* Trzecia kolumna określa nam typ filesystemu jaki znajduje się na naszym urządzeniu.
* Czwarta kolumna wpisu to pozycja rozdzielonych przecinkami opcji z jakimi dany filesystem zostanie zamountowany.
* Piąta kolumna informuje system o konieczności zrzucania filesystemu przy okazji wykonywania dump - domyślnie filesystemy nie są zrzucane (backupowane), więc opcja przybiera wartość 0 - w przeciwnym wypadku powinno to być 1.
* Ostatnia kolumna określa kolejność sprawdzania dysku przez fsck podczas restartu maszyny. Root filesystem powinien być opatrzony wartością 1 i być sprawdzany jako pierwszy. Pozostałe punkty mountowania powinny być sprawdzane później (opcja 2), lub jeśli sprawdzanie nie jest konieczne wartość powinna wynieść 0.

Najczęściej spotykaną opcją w czwartej kolumnie pliku fstab jest chyba opcja default. W rzeczywistości opcja jest aliasem dla szeregu innych: rw, suid, dev, exec, auto, nouser, async, realtime. Oczywiście zestaw opcji domyślnych może się zmieniać w zależności od wersji kernela oraz typu filesystemu.

Krótkie wyjaśnienie poszczególnych:
* rw - filesystem zamountowany do odczytu i zapisu
* suid - obsługuje bity set-user-id i set-group-id
* dev - bloki specjalne znajdujące się na takim filesystemie mogą być traktowane jako urządzenia
* exec - zezwala na wykonywanie binariów z danego filesystemu
* auto - powoduje, że filesystem będzie mountowany przy wydaniu komendy mount -a
* nouser - ogranicza możliwość mountowania filesystemu jedynie dla root-a
* async - wszystkie operacje I/O będą prowadzone asynchronicznie
* realtime - zapewnia, że daty dostępu i modyfikacji plików będą odnotowywane w systemie.

Dla większości punktów mountowania opcja default będzie wystarczająca, ale możemy podnieść bezpieczeństwo naszego systemu stosując pewne ograniczenia dla specyficznych filesystemów.
Jak zwykle po pełną listę opcji odeślę do manuala (man mount), ale wymienię kilka, które zdarza mi się wykorzystywać najczęściej:

* noexec - spowoduje, że binaria czy skrypty znajdujące się na takiej partycji nie będą mogły być na niej uruchamiane
* _netdev - informuje system, że dany zasób jest urządzeniem sieciowym i spowoduje, że mountowanie odbędzie się dopiero po uzyskaniu przez system komunikacji sieciowej (podniesienia usługi sieci)
* nosuid - nie pozwoli na zadziałanie bitów setuid i setgid
* acl - dzięki niej będziemy mogli używać kontroli dostępu opartej o ACL-e
* remount - opcja przydatna w przypadku problemów z filesystemem - pozwala na przemountowanie filesystemu z innymi opcjami niż te zawarte w fstabie.

Opcja remount wymieniona powyżej używana jest z komendą mount, i działa w dwojaki sposób, zależnie od użytej składni. Pozwala ona przemountować już zamountowany filesystem z innymi opcjami, przy czym nie zmienia ani urządzenia ani punktu mountowania. Bardzo często używana jest do przywrócenia możliwości zapisu w punkcie mountowania, który np. w wyniku błędów system operacyjny przełączył w tryb ro.

  [root@server ~]# mount -o remount,rw /tmp

Takie użycie opcji spowoduje, że mount pobierze opcje zawarte w fstabie (lub mtabie) i uzupełni je o rw, przemountowując filesystem.
Drugim sposobem użycia, o którym wspominałem jest:

[root@server ~]# mount -o remount,rw /dev/mapper/vg_centos-lv_tmp /tmp

Użycie w poleceniu zarówno ścieżki urządzenia jak i punktu mountowania spowoduje, że mount nie weźmie pod uwagę już zdefiniowanych opcji mountowania (z fstab lub mtab), a przemountuje filesystem jedynie z opcjami podanymi przez nas w komendzie.

Od linuxa 2.4.0 istnieje możliwość stosowania jeszcze jednej ciekawej i nieraz przydatnej opcji. Otóż mamy możliwość bindowania, czyli przemountowywania całości lub części już zamountowanego filesystemu w inne miejsce i z innymi opcjami. Np:

[root@server ~]# mount --bind /tmp /tmp_ro
[root@server ~]# mount | grep tmp
/tmp on /tmp_ro type none (rw,bind)
[root@server ~]# mount -o remount,ro /tmp_ro/
[root@server ~]# mount | grep tmp
/tmp on /tmp_ro type none (ro,bind)

Sposobem tym zawartość katalogu /tmp jest dostępna w systemie również w katalogu /tmp_ro, a dodatkowo ten punkt mountowania działa jedynie w trybie ro. Ten przykład jest może trochę abstrakcyjny, ale bindowanie możemy wykorzystać np: do mountowania katalogu znajdującego się w długiej ścieżce systemowej, do nowego punktu znajdującego się bezpośrednio w katalogu /.
Wpisanie bindowania w /etc/fstab wykonujemy następująco:

/katalog/bindowany      /punkt/mountowania       none        bind     0 0

Niestety bindowanie samo w sobie nie zmienia opcji mountowania, i nowy punkt będzie miał takie same opcje jak ten bindowany. Jeśli dodamy taki wpis w fstabie będziemy musieli pamiętać, aby po restarcie przemountować opcje, lub oskryptować takie działania.

Opcje metadanych

Jak wspomniałem na początku, część opcji mountowania filesystemu znajduje się w jego metadanych. Możemy je podejrzeć poprzez:

[root@rsyslog-server tmp]# tune2fs -l /dev/mapper/vg_centos-lv_root | head
tune2fs 1.41.12 (17-May-2010)
Filesystem volume name:   _CentOS-6.7-x86_
Last mounted on:          /
Filesystem UUID:          ec12b9d0-6f56-47cf-805f-a3fc5286fa12
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr
Filesystem state:         clean

Nie będę się rozpisywał nad znaczeniem ich wszystkich, ponieważ (i o tym trzeba pamiętać) opcje te mogą być nadpisywane przez opcje podawane w fstab czy mount.
Jednak dla porządku, pokażę jak je dodawać i odejmować. (opisy dostępne oczywiście w manualu man tune2fs).

Dodawanie opcji zrealizujemy przez:

[root@rsyslog-server tmp]# tune2fs -o acl /dev/mapper/vg_centos-lv_root
tune2fs 1.41.12 (17-May-2010)
[root@rsyslog-server tmp]# tune2fs -l /dev/mapper/vg_centos-lv_root | grep options
Default mount options:    user_xattr acl

Usuwanie odbywa się poprzez dodanie "daszka" przed opcją, którą chcemy usunąć:

[root@rsyslog-server tmp]# tune2fs -o ^acl /dev/mapper/vg_centos-lv_root
tune2fs 1.41.12 (17-May-2010)
[root@rsyslog-server tmp]# tune2fs -l /dev/mapper/vg_centos-lv_root | grep options
Default mount options:    user_xattr

Zarządzanie poprawkami bezpieczeństwa Red Hat

Red Hat
Firma Red Hat udostępnia dla systemów zarejestrowanych w RHN (Red Hat Network) szereg poprawek i łatek bezpieczeństwa, które powinniśmy aplikować do naszego systemu możliwie często. Łatki ze względu na funkcjonalności jakie ze sobą niosą podzielone są na trzy kategorie:

* RHSA (Red Hat Security Advisory) - poprawiające wykryte luki bezpieczeństwa, powinno się je aplikować ASAP, i traktować jako krytyczne
* RHBA (Red Hat Bug Fix Advisory) - poprawiające luki nie związane z bezpieczeństwem systemu - aplikacja ich jest zalecana, ale nie tak krytyczna jak w przypadku RHSA
* RHEA (Red Hat Enhancement Advisory) - dostarczające usprawnienia do elementów systemu.

Do zarządzania łatkami oraz ich aplikacji używać będziemy wtyczki do yum o nazwie yum-plugin-security

Wtyczkę instalujemy jak każdy inny pakiet:

[root@server ~]# yum install yum-plugin-security

Opis, ze względów technicznych (moje ćwiczenia odbywają się na CentOS, któy nie ma dostępu do RHN) nie będzie zawierał faktycznych zrzutów wyników działania poszczególnych komend, a jedynie polecenia, którymi należy posługiwać się przy zarządzaniu poprawkami.

W pierwszej kolejności pobierzemy informację o dostępnych poprawkach:

yum updateinfo

Do uzyskania informacji o dostępnych poprawkach możemy użyć trzech operatorów:

yum updateinfo list
yum updateinfo info
yum updateinfo summary

Każda z komend może być również użyta w zależności od statusu poprawek w naszym systenie:

yum updateinfo * all
yum updateinfo * available
yum updateinfo * installed
yum updateinfo * updates

Weryfikacji ile pakietów wymaga zaaplikowania poprawek bezpieczeństwa możemy dokonać przy pomocy komendy:

yum --security list updates

Wyboru poprawek do instalacji możemy dokonywać na kilka sposobów, oczywiście poza klasyfikacją przedstawioną powyżej.

Każda z poprawek opatrzona jest identyfikatorem advisory ID (np. RHSA-2013:0689) i użycie tego identyfikatora pozwoli nam zainstalować konkretną poprawkę.

System umożliwia nam również instalację poprawek naprawiających konkretną podatność CVE (np: CVE-2012-6329).
Poszczególne podatności posiadają identyfikatory i umieszczene są w bazie CVE (http://cve.mitre.org/about/).

Kolejną możliwością może być użycie identyfikatora błędu Bugzilla ID.

yum updateinfo list --advisory=RHSA-2013:0689
yum updateinfo list --cve=CVE-2012-6329
yum updateinfo list --bz=123

Nic nie stoi na przeszkodzie, aby poszukać poprawek dla konkretnego pakietu zainstalowanego w systemie:

yum updateinfo list openldap

Jako, że nie mam możliwości zacytowania outputu komend w systemie, wymieniłem tylko przydatniejsze wariacje dotyczące zarządzania poprawkami.
W zarządzaniu tym przydatny będzie manual man yum-security w którym znajdziemy zarówno przykłady jak i opisy poszczególnych dostępnych opcji.

[audit] Śledzenie programów - autrace

Red Hat 6.x / CentOS 6.x
Reguły audytowe w systemie audit stwarzają bardzo duże możliwości weryfikacji co dzieje się z naszym systemie operacyjnym. Oczywiście muszą one zostać odpowiednio zdefiniowane, ale nie o definiowaniu chciałem tu pisać, a jedynie wykorzystać istniejące oprogramowanie do zademonstrowania ich możliwości.

Istnieje w systemie aplikacja, która wykorzystując te właśnie reguły umożliwia nam śledzenie działania oprogramowania systemowego, a w zasadzie nie tyle działania, co zdarzeń, jakie takiego działania są skutkiem.

autrace bo o nim mowa wywołuje podane jako parametr polecenie, zastępując na czas tego uruchomienia standardowe reguły audit własnymi - dedykowanymi do charakteru własnego działania. Po zakończeniu przywraca wcześniejsze definicje systemowe i informuje nas z jakim PID-em test przebiegał, podając gotową komendę, którą możemy wykonanie procesu prześledzić.

[root@server ~]# autrace /bin/ls /tmp
Waiting to execute: /bin/ls
hsperfdata_pkiuser  hsqldb.wEncXsNE  hsqldb.xu7Bamgr  kde-root  krb5cc_0  orbit-gdm  orbit-root  pulse-0mK8Vejz42eO  pulse-j4H4Y7P5exeT  virtual-root.ljcOAe
Cleaning up...
Trace complete. You can locate the records with 'ausearch -i -p 11804'

Pamiętając, że ausearch wyszukuje i przedstawia w zasadzie w niezmienionej postaci linie z /var/log/audit/audit.log, analizowanie tego typu przebiegów nie wydaje się być interesujące. Z pomocą przychodzi nam jednak aureport, którego raporty są przejrzyste i proste do zinterpretowania.

Musimy wykorzystać tu jedną z opcji ausearch, pozwalającą przeglądać wyszukane zdarzenia w formacie raw (opcja --raw), który z kolei aureport bez problemu interpretuje. Wynik jednego polecenia przekażemy bezpośrednio do drugiego:

[root@server ~]# ausearch --raw -p 11804 | aureport

Summary Report
======================
Range of time in logs: 08/30/2015 09:50:01.921 - 10/08/2015 08:47:42.597
Selected time for report: 08/30/2015 09:50:01 - 10/08/2015 08:47:42.597
Number of changes in configuration: 0
Number of changes to accounts, groups, or roles: 0
Number of logins: 0
Number of failed logins: 0
Number of authentications: 0
Number of failed authentications: 0
Number of users: 2
Number of terminals: 2
Number of host names: 1
Number of executables: 3
Number of files: 15
Number of AVC's: 0
Number of MAC events: 0
Number of failed syscalls: 2
Number of anomaly events: 0
Number of responses to anomaly events: 0
Number of crypto events: 0
Number of keys: 0
Number of process IDs: 1
Number of events: 125

Teraz, bez przeszkód możemy raportować dowolne eventy towarzyszące wykonaniu standardowego ls /tmp. Jak widać z ogólnej statystyki komenda używa 15 plików lub katalogów, sprawdźmy więc jakich:

[root@server ~]# ausearch --raw -p 11804 | aureport -i -f --summary

File Summary Report
===========================
total  file
===========================
3  /selinux
2  /tmp
1  /lib64/libattr.so.1
1  /lib64/libpthread.so.0
1  /lib64/libdl.so.2
1  /lib64/libc.so.6
1  /lib64/libacl.so.1
1  /lib64/libcap.so.2
1  /lib64/librt.so.1
1  /lib64/libselinux.so.1
1  /etc/ld.so.cache
1  /etc/ld.so.preload
1  (null)
1  /bin/ls
1  /usr/lib/locale/locale-archive

Niektóre z nich używane są kilkukrotnie.... ciekawe w jakiej kolejności :)

[root@server ~]# ausearch --raw -p 11804 | aureport -i -f

File Report
===============================================
# date time file syscall success exe auid event
===============================================
1. 10/08/2015 08:47:42 /bin/ls execve yes /bin/ls root 3812
2. 10/08/2015 08:47:42 /etc/ld.so.preload access no /bin/ls root 3815
3. 10/08/2015 08:47:42 /etc/ld.so.cache open yes /bin/ls root 3816
4. 10/08/2015 08:47:42 /lib64/libselinux.so.1 open yes /bin/ls root 3820
5. 10/08/2015 08:47:42 /lib64/librt.so.1 open yes /bin/ls root 3828
6. 10/08/2015 08:47:42 /lib64/libcap.so.2 open yes /bin/ls root 3835
7. 10/08/2015 08:47:42 /lib64/libacl.so.1 open yes /bin/ls root 3843
8. 10/08/2015 08:47:42 /lib64/libc.so.6 open yes /bin/ls root 3850
9. 10/08/2015 08:47:42 /lib64/libdl.so.2 open yes /bin/ls root 3858
10. 10/08/2015 08:47:42 /lib64/libpthread.so.0 open yes /bin/ls root 3866
11. 10/08/2015 08:47:42 /lib64/libattr.so.1 open yes /bin/ls root 3874
12. 10/08/2015 08:47:42 /selinux statfs yes /bin/ls root 3901
13. 10/08/2015 08:47:42 /selinux statfs yes /bin/ls root 3902
14. 10/08/2015 08:47:42 /selinux stat yes /bin/ls root 3903
15. 10/08/2015 08:47:42 /usr/lib/locale/locale-archive open yes /bin/ls root 3906
16. 10/08/2015 08:47:42 /tmp stat yes /bin/ls root 3912
17. 10/08/2015 08:47:42 /tmp open yes /bin/ls root 3913

Kto by się spodziewał, że zwykły ls korzysta z 2 użytkowników? Ja się nie spodziewałęm, więc chętnie, przy okazji sprawdzę jakich:

[root@server ~]# ausearch --raw -p 11804 | aureport -i -u --summary

User Summary Report
===========================
total  auid
===========================
123  root
2  unset

Stosowanie samego autrace, jak mi się wydaje, jest mało przydatne. Czytanie i analizowanie logów jest męczarnią, a dla tak prostego programu jak ls log ten to niemal 180 linii. Jednak kierowanie takiego trace'a do narzędzia raportującego daje nam duże możliwości prostej i szybkiej weryfikacji, np. czy aby dana binarka nie grzebie nam w pliku, w którym nie powinna :)

[audit] Generowanie raportów audytowych - aureport

Red Hat 6.x / CentOS 6.x
System operacyjny poza możliwością wyszukiwania zdarzeń w logach audit daje nam możliwość prostego generowania raportów z tych zdarzeń. Narzędzie aureport, bo je mam na myśli, posiada sporą grupę opcji, dzięki której w czytelny sposób możemy przedstawić statystyki dla wybranego elementu, zaprezentowane w usystematyzowanej kolumnowej formie.

Jak w przypadku narzędzia ausearch tutaj również możemy wymusić interpretację niektórych pól przedstawianych w raporcie, i analogicznie będziemy to realizować przez dodanie parametru -i.

Podstawowym raportem generowanym przez aureport jest raport sumaryczny pokazujący ilościowe zestawienie zdarzeń różnego rodzaju:

[root@server ~]# aureport

Summary Report
======================
Range of time in logs: 08/24/2015 19:14:27.452 - 10/08/2015 07:21:05.686
Selected time for report: 08/24/2015 19:14:27 - 10/08/2015 07:21:05.686
Number of changes in configuration: 20
Number of changes to accounts, groups, or roles: 28
Number of logins: 56
Number of failed logins: 6
Number of authentications: 112
Number of failed authentications: 20
Number of users: 5
Number of terminals: 16
Number of host names: 8
Number of executables: 18
Number of files: 2
Number of AVC's: 7
Number of MAC events: 62
Number of failed syscalls: 0
Number of anomaly events: 6
Number of responses to anomaly events: 0
Number of crypto events: 913
Number of keys: 0
Number of process IDs: 1381
Number of events: 8933

Na jego podstawie, bez wnikania w szczegóły poszczególnych zdarzeń możemy określić np. ile nieudanych prób logowania miało miejsce w okresie czasu wymienionym w samym raporcie - domyślnie zawsze wykorzystywany jest aktualny plik logu, więc data zakończenia powinna być aktualna. Każde z wymienionych typów zdarzeń możemy, przy użyciu odpowiednich opcji uszczegółowić i wyraportować.

Przejdźmy zatem do samych opcji programu, generujących raporty w odniesieniu do różnych pól audit.log.

* -au wygeneruje nam raport z prób autentykacji w systemie, np:

[root@server ~]# aureport -au -i

Authentication Report
============================================
# date time acct host term exe success event
============================================
1. 10/08/2015 03:53:38 root 192.168.1.6 ssh /usr/sbin/sshd yes 3252
2. 10/08/2015 03:53:38 root 192.168.1.6 ssh /usr/sbin/sshd yes 3255
3. 10/08/2015 06:45:59 root 192.168.1.111 ssh /usr/sbin/sshd no 3524
4. 10/08/2015 06:45:59 root 192.168.1.111 ssh /usr/sbin/sshd no 3525
5. 10/08/2015 06:46:02 root 192.168.1.111 ssh /usr/sbin/sshd no 3526
6. 10/08/2015 06:46:02 root 192.168.1.111 ssh /usr/sbin/sshd no 3527
7. 10/08/2015 06:46:06 root 192.168.1.111 ssh /usr/sbin/sshd no 3528
8. 10/08/2015 06:46:06 root 192.168.1.111 ssh /usr/sbin/sshd no 3529
9. 10/08/2015 06:46:25 root 192.168.1.111 ssh /usr/sbin/sshd yes 3540
10. 10/08/2015 06:46:25 root 192.168.1.111 ssh /usr/sbin/sshd yes 3543
11. 10/08/2015 06:46:33 test 192.168.1.111 ssh /usr/sbin/sshd no 3565
12. 10/08/2015 06:46:33 test 192.168.1.111 ssh /usr/sbin/sshd no 3566
13. 10/08/2015 06:46:34 test 192.168.1.111 ssh /usr/sbin/sshd yes 3567
14. 10/08/2015 06:46:34 test 192.168.1.111 ssh /usr/sbin/sshd yes 3570

Z zestawienia możemy odczytać datę próby logowania, użytkownika, ip z którego próba była podjęta, jaki program został użyty, czy autoryzacja zakończyła się sukcesem oraz ID eventu audit.
Trzeba podkreślić tu fakt, że raport przedstawia próby autentykacji, czyli każdorazową weryfikacją pary user-hasło. Np. podczas logowania poprzez ssh i pomyłki przy wpisywaniu hasła dostaniemy możliwość podania hasła jeszcze raz. Pierwsza, nieudana próba wprowadzenia hasła zostanie zalogowana - sytuację taką widać powyżej - autentykacja użytkownika test o godz. 06:46:33 nie udała się (podano błędne hasło) a sekundę później zakończyła się sukcesem (podano poprawne hasło w drugiej próbie dla tej samej sesji ssh). Podwojenie wpisów jest wynikiem samego procesu autentykacji, i jest zachowaniem normalnym.

* --failed to opcja, która ograniczy nam wyniki naszego raportu jedynie do elementów, które nie zakończyły się sukcesem, i możemy stosować ją w połączeniu z bodaj wszystkimi opcjami rodzajowymi raportów (przeciwieństwem jej jest opcja --success):

[root@server ~]# aureport -au -i --failed

Authentication Report
============================================
# date time acct host term exe success event
============================================
1. 10/08/2015 06:45:59 root 192.168.1.111 ssh /usr/sbin/sshd no 3524
2. 10/08/2015 06:45:59 root 192.168.1.111 ssh /usr/sbin/sshd no 3525
3. 10/08/2015 06:46:02 root 192.168.1.111 ssh /usr/sbin/sshd no 3526
4. 10/08/2015 06:46:02 root 192.168.1.111 ssh /usr/sbin/sshd no 3527
5. 10/08/2015 06:46:06 root 192.168.1.111 ssh /usr/sbin/sshd no 3528
6. 10/08/2015 06:46:06 root 192.168.1.111 ssh /usr/sbin/sshd no 3529
7. 10/08/2015 06:46:33 test 192.168.1.111 ssh /usr/sbin/sshd no 3565
8. 10/08/2015 06:46:33 test 192.168.1.111 ssh /usr/sbin/sshd no 3566

* -l pokazuje nam statystyki logowania userów. W odróżnieniu od opcji -au przedstawione są tu faktyczne próby logowania - jeśli logowanie jest raportowane jako nieudane oznaczać to może, że np. hasło zostało podane błędnie trzykrotnie i serwer odnówił autoryzacji użytkownika, np:

[root@server ~]# aureport -l -i

Login Report
============================================
# date time auid host term exe success event
============================================
1. 10/08/2015 03:53:38 root 192.168.1.6 /dev/pts/0 /usr/sbin/sshd yes 3260
2. 10/08/2015 06:46:06 root 192.168.1.111 ssh /usr/sbin/sshd no 3533
3. 10/08/2015 06:46:25 root 192.168.1.111 /dev/pts/1 /usr/sbin/sshd yes 3548
4. 10/08/2015 06:46:35 root 192.168.1.111 /dev/pts/1 /usr/sbin/sshd yes 3579

* -c zaraportuje zmiany w konfiguracji - niezbyt czytelne i bez dalszej analizy chyba nieprzyatne

* -e wyświetli nam listę wszystkich eventóv w formie raportu

* -k wyświetli raport z występujących w logu kluczy reguł - możliwych do zdefiniowania indywidualnie wraz z niestandardowymi regułami. W przypadku, kiedy nie zdefiniowaliśmy własnych reguł ta opcja jest w zasadzie bezużyteczna, gdyż predefiniowane reguły nie używają kluczy.

* -m jest raportem przedstawiającym zmiany w kontach użytkowników. Raportowane są tu dodania kont, grup, usunięcia ich czy zmiany hasła.

* -n ciekawy raport prezentujący nietypowe w rozumieniu systemu zachowania. Co prawda sam raport nie mówi nam co spowodowało anomalię, ale daje nam możliwość zbadania tego faktu podając event ID zdarzenia, oraz dając możliwość zweryfikowania jak na taką anomalię system zareagował. Reakcję możemy sprawdzić wywołująć aureport z opcją -r.

* -p jest raportem PID-ów procesów

* -s to raport z SYSCALL-i

* --summary to bardzo przydatna opcja, pozwalająca na pogrupowanie i podliczenie wystąpień w konkretnym raporcie. Zapewnia nam dodatkową gradację szczegółowości raportów pomiędzy raportem sumarycznym i szczegółowym. Dla przykładu sumaryczny raport logowań:

[root@server ~]# aureport -i -l --summary

Login Summary Report
============================
total  auid
============================
36  root
19  test
3  unset
2  admin
2  test2

Niestety nie wszystkie raporty działają z tą opcją.
Co ciekawe, w przypadku raportów z logowań uwzględniane są nie tylko konta lokalne, ale również te autoryzujące się w źródłach zewnętrznych (jak np. w tym przypadku konta z IPA - konto admin)

* --tty wspomnianu już został przy okazji modułu pam_tty_audit. Służy do raportowania "klawiatury" użytkownika, który został w tymże module skonfigurowany.

* -tm raportuje terminale wykorzystywane przez system

* -ts [data] [godzina] to, tak jak w przypadku ausearch ogranicznik czasu wyświtlania raportu - time start. Możemy tu jako parametru użyć interesującej nas daty lub godziny, ale również aliasów: now, recent (10 minut temu), today (dziś od godz. 00:00:01), yesterday, last-week, last-month, last-year.

* -te [data] [godzina], czyli time end. Przyjmuje on parametry identyczne jak -ts

Pozostałe opcje zdają się być mniej użyteczne, ale warto je poznać, choćby dla uświadomienia sobie pełnych możliwości aureport. Standardowo w tym celu odeślę Cię do manuala systemowego, bo to nieocenione źródło informacji, które zawsze jest pod ręką.

[audit] Wyszukiwanie zdarzeń i interpretacja logów audytowych

Red Hat 6.x / CentOS 6.x
System audytowy loguje swoje wiadomości do pliku /var/log/audit/audit.log. Wpisy te zawierają dużo informacji różnego rodzaju i zależnie od typu zdarzenia jakie zaszło w systemie mogą nieznacznie różnić się pomiędzy sobą, dlatego analizowanie samego logu wymaga dokładnego wczytania się w jego treść. System oferuje różnego rodzaju narzędzia raportujące na podstawie tego logu, ale znajomość składni pliku może niekiedy okazać się przydatna.

Typowy wpis w audit.log wygląda podobnie do poniższego:

type=SYSCALL msg=audit(1440437032.702:20): arch=c000003e syscall=1 success=yes exit=1 a0=3 a1=7ffd651b08d0 a2=1 a3=7ffd651af650 items=0 ppid=2583 pid=2800 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="setenforce" exe="/usr/sbin/setenforce" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)

Możemy w nim wyróżnić kilka charakterystycznych elementów:
* type=SYSCALL to typ wiadomości audytowej. Tutaj akurat wiadomość tyczy się wywołania systemowego, ale typów tych jest wiele.
* msg=audit(1440437032.702:20) zawiera w sobie znacznik czasu oraz ID wiadomości. Znacznik czasu znajduje się przed znakiem dwukropka i wyznacza liczbę sekund "od epoki". Za dwukropkiem znajdziemy ID wiadomości.
Znacznik czasu, jeśli zachodzi taka potrzeba możemy "zdekodować" używając systemowego polecenia date:

[root@ipaclient1 ~]# date --date=@1440437032.702
Mon Aug 24 19:23:52 CEST 2015

* arch to znacznik architektury procesora w notacji hexadecymalnej - c000003e oznacza x86_64
* syscall=1 to typ wywołania systemowego
* success=yes to efekt działania tego wywołania - w naszym wypadku wywołanie zakończyło się sukcesem
* exit=1 to exit code przesłany przez nasze wywołanie
* pola a0 - a3 to pierwsze cztery argumenty danego syscalla w notacji hexadecymalnej
* items=0 informuje nas o ilości wpisów danego typu dla danego eventu
* ppid to Parent Process ID dla procesu wywołującego nasz SYSCALL
* pid to Process ID
* auid to tzw. Audit User ID, czyli oryginalny UID użytkownika który nadawany jest po jego zalogowaniu do systemu i przekazywany do końca sesji
* uid oraz gid to UID iraz GID (group ID) użytkownika, który rozpoczął proces który audytujemy
* euid oraz egid to efektywny user ID oraz group ID
* fsuid oraz fsgid to file system uid i gid
* suid i sgid  pokazują set uid oraz set gid dla procesu
* tty to oczywiście terminal z którego proces rozpoczęto
* ses to ID sesji
* comm="setenforce" to commandline'owa komenda, która została użyta do wywołania naszego procesu
* exe to oczywiście ścieżka do wykonanej binarki
* subj przedstawia nam kontekst selinuxa z jakim analizowany proces się rozpoczął
* key jest definiowanym w regule audytowej kluczem/nazwą danej reguły (bliżej poznamy podczas tworzenia własnych reguł)

Część pól ma oczywiste przełożenie na elementy procesu, więc analiza takiego wpisu nie będzie problemem, poza tym, że ilość danych spowoduje, że czas potrzebny do takiej analizy będzie dość znaczący.

Wyszukiwanie zdarzeń audit - ausearch

Paza zwykłym grepowaniem logu audit.log mamy możliwość przeszukiwania tegoż logu za pomocą narzędzia systemowego o nazwie ausearch. Ma ono taką przewagę nad zwykłym grepem, że potrafi interpretować część pól logu, np. zamieniając uid usera na jego nazwę czy prezentować datę wystąpienia w czytelnym formacie.

Najprzydatniejszymi operatorami komendy są moim zdaniem:
* -i powodujący interpretację pól logu
* -a event_id wyszukujący w logu wpisy dla konkretnego zdarzenia
* -c comm_name  wyszukujący wpisy dla konkretnej komendy commandline'a
* -k klucz wyszukująca po kluczu/nazwie reguły
* -p PID szukająca po PID procesu
* -x /sciezka/do/binariów szukająca zdarzeń generowanych przez konkretne binarium
* -ts [data] [godzina] lub -te [data] [godzina] ograniczające czasowo wyszukiwanie - ts to 'time start', analogicznie te to 'time end'. Przydatne mogą okazać się tu możliwe do użycia słowa kluczowe określające czas. Do wyboru mamy now, recent, today, yesterday, this-week, this-month oraz this-year. Aliasy, poza recent i now to czas zaczynający się 1 sekundę po północy odpowiednio dziś, wczoraj, pierwszego dnia tygodnia (zależnie od ustawień lokalnych), pierwszego dnia miesiąca czy roku. Recent oznacza 10 minut przed aktualną godziną. Oczywiście nic nie stoi na przeszkodzie, aby podać konkretną datę i godzinę (zgodnie z naszym formatem systemowym).

Opcji jest więcej, i naturalnie opisane są w manualu dla ausearch.
Korzystając z przytaczanego wcześniej wpisu sprawdźmy działanie ausearch. Na początek sprawdźmy jakie wpisy znajdziemy dla komendy setenforce:

[root@ipaclient1 ~]# ausearch -i -c setenforce
----
type=SYSCALL msg=audit(08/24/2015 19:23:52.702:20) : arch=x86_64 syscall=write success=yes exit=1 a0=0x3 a1=0x7ffd651b08d0 a2=0x1 a3=0x7ffd651af650 items=0 ppid=2583 pid=2800 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts0 ses=1 comm=setenforce exe=/usr/sbin/setenforce subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=MAC_STATUS msg=audit(08/24/2015 19:23:52.702:20) : enforcing=0 old_enforcing=1 auid=root ses=1

Możemy też zweryfikować co jeszcze w danym procesie się działo, wyszukując wpisów dotyczących konkretnego ID zdarzenia. Jak wynika z analizy pól logu ID takie znajdziemy w polu msg=audit(1440437032.702:20), i będzie nim wartość widniejąca po dwukropku:

[root@ipaclient1 ~]# ausearch -i -a 20
----
type=SYSCALL msg=audit(08/24/2015 19:23:52.702:20) : arch=x86_64 syscall=write success=yes exit=1 a0=0x3 a1=0x7ffd651b08d0 a2=0x1 a3=0x7ffd651af650 items=0 ppid=2583 pid=2800 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts0 ses=1 comm=setenforce exe=/usr/sbin/setenforce subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=MAC_STATUS msg=audit(08/24/2015 19:23:52.702:20) : enforcing=0 old_enforcing=1 auid=root ses=1
----
type=CRED_ACQ msg=audit(08/29/2015 14:57:02.602:20) : user pid=2983 uid=root auid=root ses=1 subj=unconfined_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=PAM:setcred acct=root exe=/usr/sbin/sshd hostname=192.168.1.6 addr=192.168.1.6 terminal=ssh res=success'
----
type=CRYPTO_KEY_USER msg=audit(08/31/2015 09:47:39.839:20) : user pid=2090 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2090 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'
----
type=CRYPTO_KEY_USER msg=audit(08/31/2015 09:51:39.095:20) : user pid=2081 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2081 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'
----
type=CRYPTO_KEY_USER msg=audit(08/31/2015 10:34:17.588:20) : user pid=2085 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2085 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'
----
type=CRYPTO_KEY_USER msg=audit(08/31/2015 11:03:31.530:20) : user pid=2090 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2090 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'
----
type=CRYPTO_KEY_USER msg=audit(08/31/2015 20:25:27.072:20) : user pid=2197 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2197 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'
----
type=LOGIN msg=audit(08/31/2015 20:30:21.466:20) : pid=2085 uid=root subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 old auid=unset new auid=root old ses=unset new ses=2
----
type=USER_AUTH msg=audit(09/21/2015 16:45:31.927:20) : user pid=2386 uid=root auid=unset ses=unset subj=system_u:system_r:local_login_t:s0-s0:c0.c1023 msg='op=PAM:authentication acct=root exe=/bin/login hostname=? addr=? terminal=tty1 res=success'
----
type=CRYPTO_KEY_USER msg=audit(09/22/2015 02:06:57.511:20) : user pid=2201 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2201 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'
----
type=CRYPTO_KEY_USER msg=audit(09/22/2015 22:55:13.412:20) : user pid=2196 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2196 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'
----
type=CRYPTO_KEY_USER msg=audit(09/23/2015 20:54:36.517:20) : user pid=2198 uid=root auid=root ses=1 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=97:8b:22:1c:92:9d:f9:b7:b5:96:ee:f2:c5:3b:d5:59 direction=? spid=2198 suid=root  exe=/usr/sbin/sshd hostname=? addr=192.168.1.6 terminal=pts/0 res=success'

Nie będę tu dokonywał analizy wyników zapytania, ponieważ nie to było celem tego tekstu. Opierając się na nim możesz natomiast dość sprawnie sam sprawdzić co działo się w systemie...

Pluggable authentication modules (PAM) - rejestrowanie poczynań użytkowników - pam_tty_audit

Red Hat 6.x / CentOS 6.x
Ciekawym modułem PAM pozwalającym rejestrować poczynania użytkownika w sposób wręcz paranoiczny jest pam_tty_audit.

Moduł konfigurujemy poprzez określenie jako opcji loginu lub loginów użytkowników których chemy śledzić. Działa on jedynie dla typu session, i w taki sposób go skonfigurujemy.

Konfiguracja odbywa się w znanych już plikach /etc/pam.d/system-auth oraz /etc/pam.d/password-auth:

session     optional      pam_keyinit.so revoke
session     required      pam_tty_audit.so enable=test,test2
session     required      pam_limits.so

Przytoczony powyżej przykład spowoduje logowanie działań użytkowników test oraz test2.

Do dyspozycji posiadamy opcje konfiguracyjne:
* enable= - określa oddzielone przecinkiem loginy użytkowników, których chcemy śledzić. Możliwe jest użycie wildcarda * definiującego wszystkich userów w systemie.
* disable= - loginy użytkowników, których śledzić nie chcemy
* log_passwd - standardowo nie są logowane wpisywane przez użytkownika hasła - tą opcją możemy ten stan zmienić

Kolejność wystąpienia opcji enable i disable jest istotna i determinuje zachowanie modułu. Należy pamiętać, że są parsowane w kolejności podania, a każda z nich nadpisuje listę użytkowników z poprzedniej. Inne zatem działanie będzie miała składnia enable=* disable=root logując wszystkich poza rootem, a inne disable=root enable=* logując wszystkich bez wyjątku.

Do przeglądania zalogowanych zdarzeń używać będziemy narzędzia dedykowanego do generowania raportów audytowych z usługi auditd, a mianowicie aureport. Zastosowanie opcji -i powoduje "interpretację" uid usera, czyli jego podmianę na nazwę użytkownika.

[root@server pam.d]# aureport --tty -i

TTY Report
===============================================
# date time event auid term sess comm data
===============================================
1. 10/07/2015 17:26:09 2480 test ? 331 bash <ret>,<ret>,<ret>,"ll",<ret>,"csd /.",<backspace>,<backspace>,<backspace>,<backspace>,<backspace>,"d /tmp",<ret>,"ll",<ret>,"cd o",<tab>,<ret>,"ll",<ret>,<up>,<up>,<tab>,<tab>,"g",<tab>,<ret>,"l",<backspace>,<^D>
2. 10/07/2015 18:46:47 2576 test ? 341 less "q"
3. 10/07/2015 18:46:48 2577 test ? 341 bash "test",<ret>,"man test",<ret>,<^D>
4. 10/07/2015 19:02:43 2699 test ? 348 bash "ll",<ret>,"touch test",<ret>,<^D>
5. 10/07/2015 19:02:57 2725 test2 ? 349 bash "ll",<ret>,"pwd",<ret>,"touch test",<ret>,<^D>

Jak widać na przykładzie logowanie jest bardzo dokładne i w podstawowej opcji obejmuje niciśnięcie przez użytkownika każdego klawisza, jeśli wpisywane znaki nie są częścią hasła.

Pluggable authentication modules (PAM) - dodatkowa konfiguracja modułów /etc/security

Red Hat 6.x / CentOS 6.x
Poza konfiguracją działania modułów w plikach /etc/pam.d, mechanizm PAM używa również konfiguracji zawartej w plikach znajdujących się w katalogu /etc/security. Konfiguracje te są aplikowane globalnie do odpowiadających im nazwą modułów. Działanie i przykłady użycia konfiguracji są opisane w samych plikach, oraz we właściwych manualach systemowych.

Najczęściej używanymi są access.conf oraz limits.conf, i to na nich skupię ten tekst.

Konfiguracja limitów systemowych - limits.conf

Przy użyciu tego pliku możemy zdefiniować kilka limitów systemowych dla użytkowników lub ich grup. Jak opisuje to sam plik limits.conf składnia konfiguracji wygląda następująco:

<domain>        <type>  <item>  <value>

Opis poszczególnych pól w pliku jest czytelny:
* domain - może to być użytkownik, grupa użytkowników jeśli wpis poprzedzony będzie @, lub wildcard-y % i * oznaczający wartość domyślną
* type to typ limitu - soft lub hard. Limitu hard system nie pozwoli przekroczyć, limit soft w niektórych orzypadkach może zostać przekroczony, ale zostaniemy poinformowani o tym fakcie.
* item to element, który zamierzamy limitować - wszystkie możliwości wymienione są w pliku.
* value to oczywiście wartość limitu.

Dla przykładu zdefiniujemy sobie limit jednoczesnych logowań konkretnego użytkownika. W pliku limits.conf dodajmy następującą linię:

test    hard    maxlogins 1

Nawiązanie pierwszej sesji użytkownika test przebiega normalnie, ale przy próbie nawiązania kolejnej otrzymamy komunikat:

[root@ipaclient1 ~]# ssh test@192.168.1.110
test@192.168.1.110's password:
Too many logins for 'test'.
Last login: Sat Oct  3 13:04:46 2015 from 192.168.1.111
Connection to 192.168.1.110 closed.

Kontrola dostępu poprzez access.conf

Z użyciem pliku access.conf w prosty sposób możemy ograniczyć dostęp konkretnych użytkowników z nieautoryzowanych lokalizacji, np. podsieci IP czy terminali. Sam plik konfiguracyjny pełen jest przykładów, które wystarczy dostosować do własnych potrzeb, np dodanie wpisu:

+ : test : 192.168.1.111
- : test : ALL

przydzieli dostęp (+) dla użytkownika test z jednego adresu IP (192.168.1.111) - próby zalogowania się z innych lokalizacji (ALL) zakończą się niepowodzeniem (ograniczenie dostępu poprzez -).

Należy pamiętać o jednej rzeczy. Z konfiguracji zawartej w tym pliku korzysta moduł pam_access.so, który nie jest domyślnie ładowany przez PAM - dlatego należy go dodać w plikach /etc/pam.d/password-auth oraz /etc/pam.d/system-auth:

auth        required      pam_env.so
auth        required      pam_access.so
auth        sufficient    pam_fprintd.so

Pluggable authentication modules (PAM) - blokowanie użytkowników po nieudanej próbie logowania - pam_tally2

Red Hat 6.x / CentOS 6.x
Moduł pam_tally2 to swoisty licznik nieudanych logowań użytkowników do systemu. Działanie to pozwala nam wykrywać próby złamania hasła usera i włamania na serwer. Poza monitorowaniem prób pam_tally2 pozwala nam również proaktywnie na nie odpowiadać np. poprzez blokowanie konta użytkownika dla którego wykryto zbyt dużą ilość nieudanych prób autoryzacji.

Uruchomienie procesu monitorowania logowań

Jak w przypadku wszystkich modułów pam, uruchomienie i tego wymagać będzie dodania go do odpowiedniej sekcji konfiguracji. Jako, że moduł ma nadzorować próby autoryzacji (typ auth) będzie on koniecznym (required) elementem konfiguracji dla wszelkich aplikacji dokonujących autoryzacji użytkownika w systemie, więc dodany musi zostać w plikach /etc/pam.d/system-auth oraz /etc/pam.d/password-auth. Słowem wyjaśnienia password-auth odpowiada za procesy autoryzacyjne przy zdalnym dostępie do systemu (np. ssh), system-auth natomiast za dostęp bezpośredni (np. konsola serwera).

Moduł powinien być uruchamiany przed zautoryzowaniem użytkownika, dlatego wpis należy umieścić przed modułem pam_unix, który jako sufficient po zautoryzowaniu użytkownika nie dopuści do weryfikacji modułów występujących po nim. Dodana linia wyglądać będzie następująco:

auth        required      pam_env.so
auth        required      pam_tally2.so [opcje]
auth        sufficient    pam_unix.so nullok try_first_pass

Opcje modułu

Pełną listę opcji znajdziemy oczywiście w manualu modułu. Najprzydatniejsze w moim wypadku okazały się:

* deny=N, która zablokuje dostęp do konta po N nieudanych próbach logowania. Jeśli w konfiguracji nie zdefiniowaliśmy unlock_time po zablokowaniu konto będzie musiało być odblokowane przez administratora systemu ręcznie.

* lock_time=N - definiuje czas (w sekundach) na jaki dostęp dla konta zostanie zablokowany po nieudanej próbie autoryzacji

* unlock_time=N to czas określony w sekundach, na jaki konto zostanie zablokowane po blokadzie określonej przez deny nieudanych prób logowania.

* even_deny_root spowoduje, że konto roota również będzie blokowane, tak jak zwykłe konto (domyślnie nie jest). Parametr ten używany jest najczęściej z root_unlock_time=N, który definiuje czas po jakim dostęp zostanie odblokowany.

* silent zagwarantuje brak wyświetlania informacji o logowaniu userowi

* file=/sciezka/do/pliku pozwoli nam zdefiniować inny od standardowego var/log/tallylog plik przechowywania informacji o logowaniach.

Dla przykładu zdefiniujmy sobie taką regułę:

auth        required      pam_tally2.so deny=3 lock_time=10 unlock_time=60

Jaki będzie skutek? Moduł zablokuje dostęp do konta na 10 sekund po każdej nieudanej próbie logowania (podaniu błędnego hasła). Po trzech nieudanych próbach (w tym wypadku nieudane próby liczone są co 10 sekund) na 60 sekund zostanie zablokowana możliwość zalogowania się na konto.
System nie informuje użytkownika o powodzie nieudanego logowania i każda próba po blokadzie czasowej konta wygląda, jakby wprowadzane hasło było niepoprawne.

Statystyki nieudanych logowań

Moduł posiada niewielki interfejs pozwalający administratorowi na weryfikację ilości nieudanych logowań oraz czasu i adresu źródłowego wystąpienia ostatniego z nich.

[root@ipaclient1 pam.d]# pam_tally2
Login           Failures Latest failure     From
root                1    10/02/15 17:42:15  server.ipa.local
test                8    10/02/15 17:38:41  server.ipa.local

Jak widać system odnotował 8 nieudanych prób logowania na konto użytkownika test, z czego ostatnie o 17:38:41 z maszyny server.ipa.local, oraz jedną nieudaną próbę logowania na root-a... Wyświetlane wyniki możemy ograniczyć do jednego tylko usera poprzez parametr -u username.

Dzięki interfejsowi możemy dodatkowo zrealizować jeszcze jedno zadanie, mianowicie zresetować licznik nieudanych logowań dla użytkownika. Może to być przydatne w sytuacji, kiedy sami zapomnieliśmy hasła, a nie chcemy zaciemniać statystyk nieautoryzowanych prób logowania poprzez własne nieudane próby.

[root@ipaclient1 pam.d]# pam_tally2 -u test
Login           Failures Latest failure     From
test                8    10/02/15 17:38:41  server.ipa.local
[root@ipaclient1 pam.d]# pam_tally2 --reset=4 -u test
Login           Failures Latest failure     From
test                8    10/02/15 17:38:41  server.ipa.local
[root@ipaclient1 pam.d]# pam_tally2 -u test
Login           Failures Latest failure     From
test                4    10/02/15 17:38:41  server.ipa.local

Możemy również użyć krótkiej opcji -r, która wyzeruje licznik nieudanych logowań, a w przypadku kiedy nie określimy użytkownika, dla którego licznik ma być zresetowany, uwzględnione zostaną wszystkie konta.

[root@ipaclient1 pam.d]# pam_tally2 -r
Login           Failures Latest failure     From
root                1    10/02/15 17:53:17  server.ipa.local
test                1    10/02/15 17:53:40  server.ipa.local
[root@ipaclient1 pam.d]# pam_tally2

Jak widać podczas resetowania liczników pam_tally2 wyświetla ostatni status nieudanych logowań, a następnie je zeruje.

Pluggable authentication modules (PAM) - polityki haseł z wykorzystaniem pam_cracklib

Red Hat 6.x / CentOS 6.x
Teorię konfiguracji modułów PAM poznaliśmy przy okazji tekstu Pluggable authentication modules (PAM) - składnia i konfiguracja, więc czas wykorzystać te informacje w praktyce.

Najpopularnijszym bodaj modułem PAM, a zarazem pierwszym z jakim miałem styczność jest moduł pam_cracklib.so, dzięki któremu możemy w naszym systemie definiować polityki dotyczące wymogów, jakie muszą spełniać hasła użytkowników.

Moduł ten jest domyślnie załadowany do systemu poprzez moduły /etc/pam.d/password-auth oraz /etc/pam.d/system-auth, ale konfiguracja jego jest bardzo uboga:

password    requisite     pam_cracklib.so try_first_pass retry=3 type=

Oznacza to, że pozytywne przejście modułu jest wymagane dla typu password. Jak widzimy moduł jest wywołany z trzema opcjami:
* try_first_pass - ta opcja przed spytaniem użytkownika o hasło sprawdzi, czy wcześniej zastackowane hasło nie będzie wystarczające do autoryzacji. Przy zmianie hasła chyba nie wykorzystywane
* retry=3 - określa ile razy zapytać o hasło przed zwróceniem błędu
* type= funkcja jest aliasem dla authok_type, a odpowiada za wyświetlenie części prompta zmiany hasła. Wartość nie powinna zawierać spacji. Wartość pojawi się w postaci: "New WARTOSC_ZE_ZMIENNEJ_TYPE password:" oraz "Retype new WARTOSC_ZE_ZMIENNEJ_TYPE password:" przy próbue zmiany hasła.

Jak widać, żadna z opcji nie określa warunków, jakie hasło powinno spełniać, dlatego pozwolę sobie wymienić i wdrożyć kilka najprzydatniejszych z nich. Zmiany opcji, aby mieć pewność prawidłowego działania nowych reguł należy wdrożyć w obu plikach, tj: password-auth oraz system-auth.

Opcje weryfikacji wymogów dla haseł

Wszystkich z poniższych opcji możemy używać jednocześnie, umieszczając je po sobie oddzielone spacją.

* difok=N - użycie opcji wymusza ilość znaków, którymi nowo podane hasło musi różnić się od starego hasła (domyślnie jest to 5)

Konfiguracja:

password    requisite     pam_cracklib.so try_first_pass retry=3 type= difok=3

Działanie:

-bash-4.1$ passwd
Changing password for user test.
Changing password for test.
(current) UNIX password:1qaz@WSX
New password:1qaz@WDC
BAD PASSWORD: is too similar to the old one
New password:1qaz#EDC
Retype new password:1qaz#EDC
passwd: all authentication tokens updated successfully.

* lcredit=N
* ucredit=N
* dcredit=N
* ocredit=N

Wymienione powyżej opcje determinują maksymalną ilość tzw. znaków kredytowych w haśle.Znakami tymi są odpowiednio:
     l (lowercase) - małe litery
    u (uppercase) - duże litery
    d (digits) - cyfry
    o (other) - znaki specjalne
Ważną właściwością tych opcji jest to, że określają maksymalną, a nie jak by mogło się wydawać naturalne minimalną ilość znaków danego typu w haśle. Szczęśliwie opcaj przyjmuje wartości ujemne odwracając swoje działanie, dlatego jeśli chcemy zdefiniować minimalną wymaganą ilość znaków danego typu wrtość opcji ustawiamy na wartość ujemną (np. ucredut=-3 spowoduje, że w haśle będą musiały wystąpić conajmniej 3 duże litery). Komunikat o niespełnieniu wymagań nie mówi niestety nic o wymogach jakie podawane hasło powinno spełniać. Dla przykładowej konfiguracji:

password    requisite     pam_cracklib.so try_first_pass retry=3 type= ucredit=-1 dcredit=-2

moduł będzie wymagał minimum 1 dużej litery oraz 2 cyfr. Komunikat przy niepoprawnym haśle będzie mówił:

bash-4.1$ passwd
Changing password for user test.
Changing password for test.
(current) UNIX password:
New password: smallitblog
BAD PASSWORD: is too simple
New password: sma11itBlog
Retype new password:

* minlen=N - określa jakiej minimalnie długości ma być hasło. Na pozór zastosowanie okazuje się być oczywiste i proste, ale.... moim zdaniem jest to najbardziej "skopana" opcja modułu. Czemu? Już odpowiadam. W podstawowej konfiguracji, np:

password    requisite     pam_cracklib.so try_first_pass retry=3 type= minlen=12

bash-4.1$ passwd
Changing password for user test.
Changing password for test.
(current) UNIX password:
New password: tooshort
BAD PASSWORD: is too simple

Jak się okazuje hasło długości 11 znaków, np: smallitblog będzie wystarczające do spełnienia wymagań modułu. Jest to pierwsza z ingerencji samego modułu w wymaganą długość hasła - jeśli w konfiguracji poza definicją samej minlen nie będziemy wymagać kilku klas kredytowych moduł zmniejszy wymaganą długość hasła o 1 w stosunku do zdeklarowanej przez nas.
Kolejna ingerencja w długość dotyczy również znaków kredytowych. Jeśli przy powyższej konfiguracji w naszym haśle uwzględnimy inne niż lcredit klasy kredytowe, to każda z zastosowanych klas skróci nam wymaganą długość hasła o 1, np:
    - hasło smallitblog przejdzie weryfikację dla wymaganej minimalnej długości 12 znaków
    - hasło Smallitblog przejdzie weryfikację dla 13 znaków, gdyż zastosowaliśmy jedną dodatkową klasę - dużą literę
    - hasło Smallitblo6 przejdzie weryfikację dla 14 znaków. Zastosowaliśmy 2 dodatkowe klasy - dużą literę oraz cyfrę
    - hasło Sm@llitblo6 będzie poprawne dla 15 znakowego limitu, gdyż użyliśmy wszystkich klas kredytowych - małej i dużej litery, cyfry oraz znaku specjalnego.

Przy okazji tej opcji trzeba wspomnieć o jeszcze jednej istotnej rzeczy. Cracklib ma hardkodowany drugi limit minimalnej długości 6 znaków dla hasła, który jest sprawdzany bez względu na wartość podaną przez zmienną minlem, więc jeśli chcesz używać haseł krótszych, będziesz musiał całkowicie wyłączyć weryfikację przez cracklib.

* maxrepeat=N - opcja określa maksymalną ilość powtórzeń tego samego znaku w haśle. Domyślnie ma ona wartość 0, czyli nie jest sprawdzana.

password    requisite     pam_cracklib.so try_first_pass retry=3 type= maxrepeat=1

bash-4.1$ passwd
Changing password for user test.
Changing password for test.
(current) UNIX password:
New password: smallitblog
BAD PASSWORD: contains too many same characters consecutively

* minclass=N - przy pomocy tej opcji możemy wymucić na użytkowniku użycie kilku klas znaków, przy czym nie jest brana pod uwaę ilość znaków z danej klasy, a jedynie jej wystąpienie.

password    requisite     pam_cracklib.so try_first_pass retry=3 type= minclass=3

bash-4.1$ passwd
Changing password for user test.
Changing password for test.
(current) UNIX password:
New password: SmallItBlog
BAD PASSWORD: not enough character classes

* reject_username - nie pozwoli w haśle użyć nazwy użytkownika

password    requisite     pam_cracklib.so try_first_pass retry=3 type= reject_username

bash-4.1$ passwd
Changing password for user test.
Changing password for test.
(current) UNIX password:
New password: test123
BAD PASSWORD: it is based on your username

* enforce_for_root - ta opcja wymusi na użytkowniku root spełnienie warunków jakie zdeklarowano dla haseł. Domyślnie root może ustawić dowolne hasło dla dowolnego usera.

Pluggable authentication modules (PAM) - składnia i konfiguracja

Red Hat 6.x / CentOS 6.x
PAM to mechanizm wykorzystywany przez aplikacje do weryfikacji autentykacji wykonywanych przez nie w systemie działań.

PAM przechowuje swoje pliki konfiguracyjne w kilku miejscach w systemie. Spora część konfiguracji umieszczona jest w plikach z katalogu /etc/pam.d. Domyślnie aplikacje posiadają własne pliki konfiguracji PAM umieszczone w tym katalogu, ale mogą również pośrednio korzystać z konfiguracji zawartej w innych plikach. Kolejna część konfiguracji znajduje się w katalogu /etc/security.

Konfiguracja /etc/pam.d

Pliki konfiguracyjne posiadają charakterystyczną składnię, dzielącą proces autentykacyjny aplikacji na cztery różne typy (rule types). W każdym z typów może występować sześć różnych kontrolek definiujących zachowania dla danego wpisu (PAM controls).

Możliwymi do konfiguracji typami są:
* auth - definicje tego typu są weryfikowane podczas autoryzacji aplikacji w systemie
* account - reguły weryfikujące właściwości konta użytkownika, jak np. czy konto nie wyekspirowało, czy pliki konfiguracyjne wymagane do utrzymania sesji są na miejscu itp.
* password - definiuje zachowanie się aplikacji, kiedy użytkownik próbuje zmienić własne hasło przy jej użyciu.
* session - definiują inne zachowania w obrębie sesji użytkownika lub aplikacji, jak np zapisywanie informacji do logów, wczytywanie reguł selinuxa czy dostępy do urządzeń.

Kontrolki występujące w konfiguracji:
* required - pozytywne przejście tej reguły jest wymagane, aby uzyskać autentykację w danej aplikacji. Bez względu na wynik system przeprowadzi weryfikację pozostałych reguł, a użytkownik zostanie poniformowany o błędzie po ich przejściu.
* requisite - opcja podobna do required - wymagana do pozytywnego przejścia, jednak w przypadku błędnego wyniku reguła spowoduje przekazanie kontroli do aplikacji bez weryfikacji pozostałych reguł.
* sufficient - reguła, której przejście nie musi zakończyć się sukcesem, ale jeśli tak się stanie, i poprzedzające ją reguły required nie zwróciły błędu, żadna kolejna reguła danego typu nie będzie sprawdzana i zostanie wykonana autoryzacja.
* optional - wynik weryfikacji danej reguły nie ma wpływu na przebieg weryfikacji autoryzacji danego typu, chyba, że nie występują inne reguły danego typu.
* include - reguła dołączająca wpisy konfiguracyjne danego typu z innego pliku. Weryfikacja reguł z dołączonego pliku determinuje sukces lub błąd reguły include.
* substack - opcja podobna do include z jedną zasadniczą różnicą. W przypadku niepowodzenia weryfikacji jednej z opcji załączonej w ten sposób zakończy weryfikację innych reguł w dołączonym pliku, a proces przejdzie do kolejnej reguły z pliku głównego.

Składnia reguł umieszczonych w plikach wygląda następująco:

typ        kontrolka    nazwa_modułu    opcje_modułu

 Moduł w rzeczywistości jest biblioteką pam, która w zależności od systemu powinna znajdować się w lokalizacji /lib/security lub /lib64/security. Opcje modułu, jeśli takie wystąpią znajdziemy w większości przypadków dość dobrze opisane w manualu danego modułu.

Tyle suchej teorii, która nie wygląda zbyt zrozumiale, dlatego dla przykładu przeanalizujmy jedną z istniejących w systemie konfiguracji, np: /etc/pam.d/su. Zawartość pliku przedstawia się następująco:

[root@ipaclient1 security]# cat /etc/pam.d/su
#%PAM-1.0
auth            sufficient      pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth           sufficient      pam_wheel.so trust use_uid
# Uncomment the following line to require a user to be in the "wheel" group.
#auth           required        pam_wheel.so use_uid
auth            include         system-auth
account         sufficient      pam_succeed_if.so uid = 0 use_uid quiet
account         include         system-auth
password        include         system-auth
session         include         system-auth
session         optional        pam_xauth.so

Jak widać program su ma zdefiniowane reguły dla wszystkich rule types. W naszym śledzeniu skupimy się na jednym, a mianowicie auth.

Typ auth, jako wystarczające do autentykacji (sufficient) podaje poprawne przejście modułu pam_rootok.so. Moduł ten autentykuje użytkownika, jeśli ten jest rootem (id=0), i faktycznie dla su ten warunek autoryzacji jest spełniany (root zawsze może zrobić su). W przypadku, kiedy użytkownik nie jest rootem kolejna reguła definiuje, iż do autoryzacji będzie dołączony plik system-auth. Zerknijmy zatem w reguły typu auth zawarte w tym pliku:

[root@ipaclient1 security]# cat /etc/pam.d/system-auth | grep ^auth
auth        required      pam_env.so
auth        sufficient    pam_fprintd.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        sufficient    pam_sss.so use_first_pass
auth        required      pam_deny.so

W pierwszej kolejności moduł próbuje ustawić zmienne środowiskowe (pam_env). Kolejnym elementem jest moduł pam_fprintd, który w środowisku graficznym odpowiada za czasowe przetrzymywanie (cacheowanie) danych użytkonika root w sesji (fingerprint daemon) i nie jest on wykorzystywany w wersji tekstowej systemu. Jeśli nie mamy zcacheowanych credentiali roota przechodzimy do reguły wywołującej pam_unix.so, który to moduł odpowiada za tradycyjną autoryzację hasłem - jeśli autoryzacja ta przebiegnie pomyślnie to reguła, jako wystarczająca zautoryzuje nas do wykonania aplikacji su. Jeśli poprzednie reguły sufficient nie zakończą się sukcesem zostanie zweryfikowany uid użytkownika. Moduł pam_succeed_if sprawdzi, czy nasz użytkownik ma uid większe niż 500 (nie jest usługą systemową) - jeśli tak nie będzie, zwróci błąd autoryzacji. Po poprawnej weryfikacji id usera spróbujemy uzyskać autentykację za pomocą usługi SSSd (System Security Services daemon), która odpowiada za zdalną autentykację, np z LDAP-a, AD czy kerberosa.
Jeśli ten moduł nie zautentykuje nas, wykonany zostanie pam_deny, czyli system odmówi autentykacji dla aplikacji su.

Taką analizę można przeprowadzić samemu dla każdego z plików i każdego typu. Bardzo przydatne do tego będą manuale modułów.

Konfiguracja /etc/security

Pliki zawarte w tym katalogu przypominają bardziej klasyczne pliki konfiguracyjne spotykane w systemach linuksowych. Wszystkie z nich zawierają opis i przykładowe użycia w samym pliku, ale również manuale dokładniej opisujące ich przeznaczenie.
Sama składnia nie jest tak usystematyzowana jak w przypadku modułowych pam.d, ale nie jest również nietypowa, dlatego nie powinna wymagać dodatkowych wyjaśnień. W późniejszym czasie pojawi się tekst z kilkoma przykładowymi zmianami, które mogą okazać się przydatne w pracy administratora.

Kilka uwag na koniec

PAM jest bardzo istotnym dla poprawnego działania systemu mechanizmem, dlatego przy jakiejkolwiek ingerencji zalecana jest ostrożność. Warto, przed edycją plików wykonać ich kopię zapasową, a podczas wprowadzania zmian zawsze zapewnić sobie dodatkowe okienko z aktywną sesją roota. Błąd składniowy w niektórych modułach, lub usunięcie plików konfiguracyjnych może spowodować konieczność odzyskiwania konfiguracji z backupu lub rzeźbę w rescue mode.

W przypadku zabawy z pam.d nieocenionym narzędziem okazuje się man -k, a dokładniej man -k pam, któy pozwoli nam przejrzeć wszystkie moduły dostępne dla pam-a.

PS. Tyle suchej teorii, mało atrakcyjnej i raczej słabo przyswajalnej bez konkretnych przykładów zastosowań. W kolejnych tekstach przejdziemy do konfiguracji konkretnych modułów i zaczniemy wykorzystywać możliwości, jakie PAM nam daje. Będzie o wiele ciekawiej.... (mam nadzieję).

Ustawienia konsoli graficznej GDM (gconftool-2)

Red Hat 6.x / CentOS 6.x
Konsola graficzna w systemach serwerowych nie jest typowym przypadkiem, jednak konfiguracja jej opcji, może nie w sposób oczywisty, ale wchodzi w zakres wiedzy Expertise in Server Hardening, czyli egzaminu EX413.
Temat, poza tym, że rzadko wykorzystywany w codziennej pracy administratora, wydaje się być również dość skomplikowany ze względu na złożoność komend w celu konfiguracji wykorzystywanych. Jednak możliwość bezpośredniej edycji plików konfiguracyjnych może w niektórych przypadkach uprościć nam życie.

Dla przykładu możemy np. wyłączyć wyświetlanie listy userów w graficznym oknie logowania. Lista ta oryginalnie wygląda mniej więcej tak:


Możemy wybrać użytkownika na jakiego chcemy się zalogować do systemu. Wyświetlając nazwy wszystkich użytkowników systemu ułatwiamy jednak potencjalne ataki, np.  typu brute-force na nasz system, dlatego warto takiej listy się pozbyć. Komenda służąca takiej zmianie nie wygląda zbyt user-friendly:

[root@ipaclient1 ipa]# gconftool-2 --direct --config-source xml:readwrite:/etc/gconf/gconf.xml.defaults --type bool --set /apps/gdm/simple-greeter/disable_user_list true

Wprowadzone w ten sposób zmiany nie wymagają restartu maszyny, ale widoczne będą dopiero po wylogowaniu z aktywnych podczas wprowadzania zmian sesji.

Wynikiem działania komendy będzie zmiana ekranu logowania do systemu na wyglądający podobnie do tego:


Efekt jest zadowalający, ale już wpisanie komendy powoduje spore problemy, nie wspominając o jej zapamiętaniu.
Jako, że z natury nie lubię zawracać sobie głowy rzeczami, które przydadzą mi się zaledwie kilka razy, postanowiłem poszperać po plikach, aby ułatwić sobie wprowadzanie zmian w środowisku graficznym. Okazało się, że sporo zmian można wprowadzić edytując jeden z plików konfiguracyjnych, a same zmiany nie wymagają pamiętania nader długich komend.
Dla osób nie znających choć w podstawowym zakresie charakterystyki języka xml edytowanie tego typu plików może mieć destrukcyjny skutek, dlatego warto zrobić kopię zapasową pliku

Plikiem domyślnym konfiguracji dla środowiska - niezależnie od języka - jest /etc/gconf/gconf.xml.defaults/%gconf-tree.xml. Edycja części opcji (odpowiadających za włączenie lub wyłączenie jakiegoś elementu) polega na nadaniu wartości true odpowiedzialnemu za dany element wpisowi konfiguracji.
Przykładem niech będzie pokazane wcześniej blokowanie listy userów. Wpis odpowiedzialny za element nazywa się disable_user_list i tak jak wszystkie pozostałe, samą nazwą sugeruje za co może być odpowiedzialny.
Oryginalnie wpis w konfiguracji dla tego elementu wygląda następująco:

<entry name="disable_user_list" mtime="1443663788" schema="/schemas/apps/gdm/simple-greeter/disable_user_list"/>

Aby ukryć listę użytkowników musimy mu nadać wartość true, a zrealizujemy to rozszerzając tag entry o dodatkowe elementy:

<entry name="disable_user_list" mtime="1443663788" schema="/schemas/apps/gdm/simple-greeter/disable_user_list" type="bool" value="true"/>

Wartość zawsze występuje w parze z deklaracją typu, i całą deklarację znajdziemy prosto wyszukując w pliku frazę "true".
Plik gconf-tree.xml zawiera również nieco szersze wytłumaczenie spodziewanego działania danej opcji - w innej sekcji tego xml-a znajdują się opisy poszczególnych tagów - np, przeszukując dalej plik po disable_user_list natrafimy na taki tag:

<entry name="disable_user_list" mtime="1438965753" type="schema" stype="bool" owner="gdm-simple-greeter" gettext_domain="gdm">
    <local_schema locale="C" short_desc="Do not show known users in the login window">
        <default type="bool" value="false"/>
        <longdesc>Set to true to disable showing known users in the login window.</longdesc>
    </local_schema>
</entry>

Sam opis tagu w tej sekcji pokazuje nam również, z jakiego typu zmienną mamy do czynienia (stype).

Dla przetestowania słuszności założenia dodajmy wartość do kolejnego elementu konfiguracji, a mianowicie disable_restart_buttons. Jak sugeruje nazwa oraz opis w pliku, opcja wyłączy wyświetlanie klawiszy umożliwiających restart maszyny z ekranu logowania. Rozszerzony wpis będzie wyglądał następująco:

<entry name="disable_restart_buttons" mtime="1438965753" schema="/schemas/apps/gdm/simple-greeter/disable_restart_buttons" type="bool" value="true"/>

Efektem powinno być zniknięcie ikony restartu pierwotnie znajdującej się w prawym dolnym rogu:


W analogiczny sposób, choć nieco rozszerzony rozwiązać możemy edycję opcji typu string. Dla przykładu ustawmy w oknie logowania własną wiadomość.
Takie działanie będzie od nas wymagać zmiany dwóch parametrów - po pierwsze musimy włączyć wyświetlanie tekstu bannera (tag banner_message_enable), a po wtóre musimy tekst taki zdefiniować (tag banner_message_text).

Tag banner_message_enable jest typu bool i jego zmiana przebiega identycznie jak poprzednich:

<entry name="banner_message_enable" mtime="1438965753" schema="/schemas/apps/gdm/simple-greeter/banner_message_enable" type="bool" value="true"/>

Odmienny typ (string) ma natomiast tag banner_message_text, który zmienić musimy w sekcji, w której znajdziemy również jego opis:

<entry name="banner_message_text" mtime="1438965753" type="schema" stype="string" owner="gdm-simple-greeter" gettext_domain="gdm">
    <local_schema locale="C" short_desc="Banner message text">
        <default type="string">
            <stringvalue>Ustawiłem sobie tekst powitania</stringvalue>
        </default>
        <longdesc>Text banner message to show on the login window.</longdesc>
    </local_schema>
</entry>

Nasze zmiany odniosą następujący skutek:


W konfiguracji gdm występują jeszcze tagi o innych typach danych, ale nigdy nie miałem potrzeby ingerowania w nie, dlatego darowałem sobie sprawdzanie i opisywanie ich.

Centralna autentykacja - reguły sudo w IPA

Red Hat 6.x / CentOS 6.x
Centralna autentykacja pozwala nam z jednego miejsca zarządzać dostępami dla użytkowników. Oczywistym rozszerzeniem możliwości kontrolowania samych dostępów dla użytkowników jest zarządzanie ich rozszerzonymi uprawnieniami sudo.

Ipa oferuje możliwość definiowania reguł sudo dla użytkowników czy grup użytkowników i zaaplikowanie ich na konkretny host lub grupę hostów. Samo konfigurowanie reguł można przeprowadzić przez webowy panel administracyjny IPA (dla leniwych), lub poprzez shella (dla ambitnych). U mnie lenistwo przewyższa ambicję ;).

Aby rozwiązanie to mogło być wykorzystane konieczna będzie dodatkowa konfiguracja zarówno po stronie serwera IPA jak i hosta-klienta.

Konfiguracja serwerów do używania zdalnych plików sudoers

Pierwszym krokiem jaki musimy wykonać (jednorazowo dla każdej domeny ipa) jest zdefiniowanie hasła dla użytkownika sudo. Jako, że definicje użytkownika rezydują w ldap-ie, użyjemy komendy ldappasswd:

[root@server ipa]# ldappasswd -Y GSSAPI -S -h server.ipa.local uid=sudo,cn=sysaccounts,cn=etc,dc=ipa,dc=local
New password: {haslo_sudo}
Re-enter new password: {haslo_sudo}
SASL/GSSAPI authentication started
SASL username: admin@IPA.LOCAL
SASL SSF: 56
SASL data security layer installed.

Credentiali tych używać będziemy do konfiguracji autentykacji na wszystkich hostach klienckich. Przejdźmy zatem do ich konfiguracji (tą powtarzamy na wszystkich maszynach korzystających z logowania poprzez IPA).

W pierwszej kolejności musimy odblokować możliwość korzystania przez system ze zdalnego sudoers. Odbywa się to przez edycję pliku /etc/nsswitch.conf, a dokładniej dodanie ldap do definicji sudoers:

[root@ipaclient1 ipa]# vi /etc/nsswitch.conf
...
sudoers: files ldap sss
...

Kolejnym krokiem będzie konfiguracja samego ldap-a z którego sudo ma korzystać:

[root@ipaclient1 ipa]# vi /etc/sudo-ldap.conf
 
binddn uid=sudo,cn=sysaccounts,cn=etc,dc=ipa,dc=local
bindpw 1qazXSW@
ssl start_tls
tls_cacertfile /etc/ipa/ca.crt
tls_checkpeer yes
uri ldap://server.ipa.local
sudoers_base ou=SUDOers,dc=ipa,dc=local
bind_timelimit 30
timelimit 30

Powyższe linie należy odkomentować i zmodyfikować (elementy wymagające modyfikacji zaznaczyłem na żółto). bindpw to hasło, które ustawialiśmy wcześniej dla sudo. Pozostałe pozycje są raczej oczywiste.

Pozostaje nam jeszcze definicja domeny NIS - zalecana przez Red Hat, choć całość w podstawowej wersji działa również bez tego:

[root@ipaclient1 ipa]# vi /etc/rc.d/rc.local
...
nisdomainname ipa.local
...

Jako, że dane są w zasadzie stałe dla wszystkich maszyn-klientów, w prosty sposób możemy oskryptować te działania, ułatwiając sobie pracę.

Definiowanie reguł sudo poprzez panel www IPA

Całością konfiguracji sudo od strony panelu administracyjnego IPA zarządzamy w zasadzie poprzez trzy zakładki umieszczone w Policy > Sudo:


Definiowanie reguł sudo rozpoczynamy od określenia komendy jaka ma być przez taką regułę obsługiwana:


Definicja ta zawierać musi pełną komendę jaką użytkownik będzie mógł wykonać poprzez sudo, np /bin/cat /etc/shadow. Ważne jest, żeby poszczególne komendy (jak w tym wypadku cat) podawać z pełną ścieżką w systemie, gdyż inaczej sudo może nie zadziałać.

TIP: Jeśli nie wiesz w jakiej lokalizacji znajduje się dana binarka możesz użyć polecenia which komenda.

Kolejnym poziomem - opcjonalnym - mogą być grupy sudo. Możemy tu zebrać w jeden kontener kilka zdefiniowanych komend, aby posługiwać się nimi podczas tworzenia reguł. Podczas tworzenia grupy definiujemy jedynie jej nazwę, a po utworzeniu uzupełniamy o komendy, które chcemy w grupie umieścić.

Ostatnim poziomem jest utworzenie właściwej reguły sudo, która precyzuje komendy, użytkowników oraz hosty, na których ma działać.
Sudo rules > Dodaj wywoła proste okno, w którym zdefiniujemy nazwę reguły. Warto w nazwie zawierać możliwie dużo zwięzłych informacji, aby przy wielu regułach nie mieć problemów z ich identyfikacją, np:


Po zdefiniowaniu możemy przejść do ustawień reguły, poprzez kliknięcie na jej nazwę. Konfiguracja odbywa się na jednej stronie posegregowanej w kilka sekcji:

* General - opis reguły
* Options - opcje komendy sudo
* Who - definicje użytkowników uprawnionych do korzystania z reguły
* Access this host - definicje hostów na których reguła ma działać
* Run commands - komendy które mogą być uruchamiane w ramach reguły
* As whom - z uprawnieniami jakiego usera komenda ma być wykonana (domyśnie jest to root).

Wszystkie sekcje poza Options umożliwiają wybranie zdefiniowanych wcześniej pozycji, np. hostów, grup hostów, użytkowników, komend itd. Wszystkie z nich mają również checkbox "Any", umożliwiający wybranie wszystkich możliwości z danej sekcji (poniżej na żółto). Ja zgodnie z nazwą skonfigurowałem regułę, aby na wszystkich hostach pozwalała wykonać cat na /etc/shadow:


Jak widać uprawnienia do reguły posiada jedynie user test1.

Ważnym elementem definicji reguł są opcje sudo, które możemy uwzględniać w każdej z nich z osobna. Wszystkie opcje opisane są na stronie manuala sudo choć mało która jest używana często.

Do używanych najczęściej bez wątpienia należy odpowiednik "NOPASSWD" z tradycyjnego pliku /etc/sudoers, czyli !authenticate. Opcja pozwala wykonywać użytkownikowi sudo nie wymagając od niego żadnej dodatkowej autoryzacji:


Po tych definicjach możemy zweryfikować działanie naszej reguły logując się na dowolny host jako user test1 i porównując działania komendy z oraz bez sudo:

[root@ipaclient1 ipa]# su test1
sh-4.1$ cat /etc/shadow
cat: /etc/shadow: Permission denied
sh-4.1$ sudo cat /etc/shadow
root:$6$12o5DXryNHU2IFiH$NzNc/EU8SonPDxDNHFDjbdK6JCVMoaGd99BJ8L9xz6mRyiLkCkY4cPNpDWgvc91aXgcwHzDN4e9WKEIH3XCAs.:16671:0:99999:7:::
bin:*:15980:0:99999:7:::
daemon:*:15980:0:99999:7:::
adm:*:15980:0:99999:7:::
lp:*:15980:0:99999:7:::
sync:*:15980:0:99999:7:::
shutdown:*:15980:0:99999:7:::
halt:*:15980:0:99999:7:::
...

Użytkownik będąc zalogowanym na serwerze może zweryfikować swoje upranienia sudo w zwyczajny sposób, tj. poprzez sudo -l.

Jedną z koniecznych reguł będzie dla każdego administratora uzyskanie pełnego dostępu do własnych systemów. W IPA osobne omawianie tematu nie jest chyba konieczne. Po prostu zdefiniuj komendę jako Any Command, nie zapomnij o !authenticate i dobrej nazwie, np:


Zarządzanie logami systemowymi (logrotate) - rotowanie logów

Red Hat 6.x / CentOS 6.x
Ważnym aspektem dbania o porządek w logach systemowych jest ich rotacja. Bez niej pliki rosłyby do niebotycznych rozmiarów zapychając nam filesystem. Na szczęście z pomocą przychodzi nam logrotate, który uruchamiany cyklicznie przez cron porządkuje nam pliki.

Konfiguracja logrotate odbywa się poprzez pliki /etc/logrotate.conf oraz /etc/logrotate.d/*. Każdy instalowany pakiet może umieścić swoje definicje rotacji logów w katalogu /etc/logrotate.d nie ingerując w zawartość głównego pliku konfiguracyjnego.

Struktura konfiguracji rotacji sprowadza się do zdefiniowania kilku opcji, które opisane są w manualu dla logrotate. Możemy zdefiniować częstotliwość rotacji w odstępach czasowych (daily, weekly, monthly lub yearly) lub po uzyskaniu przez log zadanej zajętości (opcje size, minsize oraz maxsize). Przy użyciu opcji rotate możemy określić ilość archiwalnych plików pozostawionych w systemie, a użycie compress pozwala na automatyczne gzipowanie zrotowanych logów. Możemy również definiować takie opcje jak uruchamianie skryptów przed i po rotacji pliku, adres email na który mają być wysyłane zrotowane logi, oraz kilkanaście innych.

Przykładowa konfiguracja może wyglądać następująco:

[root@rsyslog-server logrotate.d]# vi remote_rsyslog
/var/log/rsyslog-server/*
{
    create 0600 root root
    weekly
    rotate 10
    minsize 1M
    compress
}

Powyższy przykład realizuje cotygodniową(weekly) rotację wszystkich logów zapisywanych do katalogu /var/log/rsyslog-server/, jeśli ich objętość jest większa niż 1Mb (minsize). Nowe pliki logów będą tworzone z uprawnieniami rw dla użytkownika root (create). Po rotacji logi zostaną skompresowane (compress), a w systemie pozostanie 10 najnowszych logów (rotate).

Określenie takich definicji jest możliwe zarówno dla pojedynczego pliku, wszystkich plików w danym katalogu, ale również dla kilku niezależnie ulokowanych plików . Aby zastosować reguły dla kilku plików należy umieścić ich nazwy w kolejnych liniach przed definicjami rotacji, np:

/var/log/rsyslog-server/cups
/var/log/rsyslog-server/sshd
/var/log/rsyslog-c1/cups
/var/log/rsyslog-c1/sshd
/var/log/rsyslog-c2/sshd
{
    daily
    rotate 10
    minsize 1M
    compress
}

Standardowo po zrotowaniu pliku dodawana jest na końcu jego nazwy kolejna cyfra. Możemy przedefiniować to zachowanie, używając jako wyróżnika daty rotacji. Służą do tego dwie opcje: dateext, który informuje rsyslog, że chcemy używać dat, oraz dateformat, który zdefiniuje nam format w jakim data będzie zapisywana, np:

/var/log/rsyslog-server/*
{
    weekly
    rotate 10
    dateext
    dateformat -%Y%m%d
}

Domyślnym formatem daty jest właśnie -%Y%m%d, czyli -{rok}{miesiac}{dzien}, i jeśli jest on dla nas zadowalający, możemy pominąć parametr dateformat.

Logrotate zapisuje daty ostatniej rotacji poszczególnych logów w pliku /var/lib/logrotate.status, więc w każdej chwili możemy podejrzeć kiedy dany plik był ostatnio zrotowany.

Zarządzanie logami systemowymi (rsyslog) - filtrowanie i przekierowywanie logów do plików

Red Hat 6.x / CentOS 6.x
Filtrowanie logów systemowych i przekierowywanie ich części do różnych plików jest bardzo rozbudowanym tematem. Kompleksowe jego poznanie wymaga pewnie wielu godzin spędzonych z dokumentacją, ale taka znajomość dla zwykłego administratora nie jest sprawą najwyższej wagi. Zaprezentuję tu jak można zrealizować najczęstsze (czyt: takie, które kiedykolwiek miałem okazję realizować) przypadki rozdzielania logów w zależności od ich ważności czy pochodzenia.
Całość konfiguracji przeprowadzamy oczywiście w pliku /etc/rsyslog.conf

Filtrowanie logów podsystemów

Filtrowanie logów pochodzących z jakiegoś podsystemu lub o zadanym priorytecie jest chyba najprostsze do realizacji, między innymi dlatego, że gotowy szablon tego rozwiązania mamy już umieszczony w /etc/rsyslog.conf.

Definicje filtrów opierają się o tzw. selektory i mają format FACILITY.PRIORITY.

FACILITY określa podsystem, który produkuje dany wpis, i może przyjmować wartości (słowne lub numeryczne): kern (0), user (1), mail (2), daemon (3), auth (4), syslog (5), lpr (6), news (7), uucp (8), cron (9), authpriv (10), ftp (11) oraz local0 do local7 (16-23).

PRIORITY jak sama nazwa wskazuje to priorytet wiadomości, o możliwych wartościach: debug (7), info (6), notice (5), warning (4), err (3), crit (2), alert (1), oraz emerg (0).

Dla obu pozycji możliwe jest użycie znaku *, który wskazuje na wszyskie facilities lub priorities.

Dla przykładu, weźmy dwa wpisy z pliku odpowiedzialne za filtrowanie.

# Log all the mail messages in one place.
mail.*                                                  -/var/log/maillog

# Log cron stuff
cron.*                                                  /var/log/cron

Pierwszy wpis zgodnie z komentarzem umieszcza wszystkie logi facility mail w dedykowanym pliku, drugi robi to samo z logami pochodzącymi z cron-a.
Oba wpisy różnią się w swojej składni minusem przed ścieżką pliku docelowego. Umieszczenie minusa przed nazwą pliku spowoduje, że log taki będzie zapisywany synchronicznie.

Możliwe jest również definiowanie wielu pozycji w jednej linii. Jeśli potrzebujemy zdefiniować kilka priorytetów dla jednego facility, wartości oddzielamy od siebie przecinkiem, np:

mail.info,debug                               /var/log/mail.info

Definiowanie przekierowania kilku facilities do jednego pliku, użyjemy średnika, np:

mail.crit;kern.crit                             /var/log/critical

Dodatkowo istnieje możliwość użycia operatora wykluczenia w postaci wykrzyknika. Taki wpis przekeiruje wszystkie logi facility, oprócz debug oraz notice:

 daemon.!debug,!notice                            /var/log/deamons

Filtrowanie logów zależnie od ich właściwości

Drugim typem filtrowania jakiego możemy użyć jest filtr oparty o właściwości wpisów. Ma on odmienną konstrukcję od prezentowanego wcześniej, a jego schemat wygląda następująco:

:wlasciwosc, operator-porownania, "wartosc"

Właściwości jak i operatory są odgórnie zdefiniowane, a pełna ich lista jest dostępna w pliku /usr/share/doc/rsyslog-5.8.10/property_replacer.html.

Najczęściej używanymi właściwościami są:
* msg czyli typ wiadomości
* fromhost - pochodzące z konkretnego hosta (przy logowaniu z serwerem centralnym)
* fromhost-ip - pochodzące z konkretnego IP
* programname - generowane przez konkretny program

Operatorami porównania mogą być:
* isequal
* contains
* startswith
* regex

Nazwy samych operatorów opisują doskonale realizowane przez nie porónania, więc nie ma sensu tego tłumaczyć.Opcjonalnie możemy przed operatorem użyć znaku negacji !.

Wartością w regule może być dowolny ciąg znaków, którego będziemy wyszukiwać w danym wpisie.

Dla przykładu utworzymy filtr oddzielający logi konkretnego programu.

Do utworzenia takiego filtra należy zidentyfikować pod jaką nazwą dany program występuje w procesie logowania. Możemy posłużyć się wpisami w /var/log/messages, gdzie każdy z programów przedstawia się nazwą w piątej kolumnie (po miesiącu, dniu, godzinie i hostname'ie), np:

Sep 23 05:01:53 rsyslog-c1 sshd[3591]: Accepted password for root from 192.168.1.6 port 61960 ssh2
Sep 23 06:29:23 rsyslog-c1 su: pam_unix(su-l:session): session opened for user test by root(uid=0)

Oczywiście w konfiguracji filtra pomijamy pid procesu zawarty w nawiasie.
Przyjmijmy, że chcemy w osobnym pliku umieszczać logowania poprzez ssh, oraz w jeszcze innym wszelkie zmiany użytkownika w trakcie sesji, czyli reagować na su. Konfiguracja jest oczywista:

:programname, isequal, "sshd"                           /var/log/sshd
:programname, isequal, "su"                             /var/log/su

Kolejnym przykładem może być filtrowanie wszystkich logów, zawierających jakiś błąd. Filtr taki będzie mieć postać:

:msg, contains, "error"                          /var/log/errorlog

Odfiltruje wszystkie wiadomości zawierające słowo kluczowe error i umieści w odrębnym pliku.

Taka składnia może być przydatna w przypadku serwera centralnego rsyslog. Umożliwia ona rozdzielenie logów pochodzących z różnych hostów na osobne pliki, np odnosząc się do naszej przykładowej realizacji centralnego rsysloga:

:fromhost, isequal, "rsyslog-c1.my.domain"        /var/log/rsyslog-c1/messages

Regułka przekieruje wszytkie wpisy z hosta rsyslog-c1.my.domain do pliku /var/log/rsyslog-c1/messages

Filtry warunkowe

Filtrów warunkowych możemy użyć do łączenia kilku filtrów właściwościowych opisanych wcześniej, oraz umieszczania ich w pętlach if-else. Ja nie potrzebuję na codzień bardzo zaawansowanych filtrów, dlatego najczęściej używam ich do przekierowywania logów przesyłanych do serwera centralnego.
Z pomocą prostego warunku możemy umieszczać różne logi z hosta zdalnego w różnych plikach., np:

if $programname == 'sshd' and $fromhost == 'rsyslog-c1.my.domain' then /var/log/rsyslog-c1/sshd
:fromhost, isequal, "rsyslog-c1.my.domain"        /var/log/rsyslog-c1/messages

Oddzielimy w ten sposób logi generowane przez sshd na maszynie rsyslog-c1 do oddzielnego pliku, podczas gdy wszystkie logi z tego hosta trafiają do pliku messages w tym samym katalogu.

Pomijanie zapisanych pozycji

Testując powyższą przykładową konfigurację na serwerze można zauważyć, że wpisy dotyczące sshd pojawiają się w pliku /var/log/rsyslog-c1/sshd, ale niepotrzebnie dublują się również w pliku /var/log/rsyslog-c1/messages. Jest na to prosta rada - po zapisaniu części logów do pliku należy poinformować rsyslog, że nie chcemy ich już więcej używać:

if $programname == 'sshd' and $fromhost == 'rsyslog-c1.my.domain' then /var/log/rsyslog-c1/sshd
if $programname == 'sshd' and $fromhost == 'rsyslog-c1.my.domain' then ~
:fromhost, isequal, "rsyslog-c1.my.domain"        /var/log/rsyslog-c1/messages

Znak tyldy w ścieżce zapisu logu spowoduje usunięcie pozycji z pamięci rsyslog.

Dynamiczne generowanie nazw plików

Podczas używania serwera centralnego dość szybko znudzi się nam ręczne określanie nazw plików i tworzenie reguł dla każdego hosta zdalnego z osobna. Pomocna okazuje się tutaj możliwość dynamicznej definicji nazw plików.

Proces polega na określeniu szablonu nazwy w oparciu o zmienne elementy logów. Elementami mogą być (lista zawiera te najczęściej wykorzystywane, a pełną można znaleźć "googlając" hasło RSYSLOG_DebugFormat):
* %FROMHOST% - czyli przesłane z hosta
* %FROMHOST-IP% - przełane z IP
* %HOSTNAME% - hostname zawarty w logu
* %syslogtag% - tag wiadomości
* %programname% - nazwa programu generującego log
* %PROCID% - id procesu
* %MSGID% - id wiadomości (wg standardu IETF)
* %TIMESTAMP% - znacznik czasu z wiadomości
* %msg% - treść wiadomości

Sama definicja szablonu nazwy takiego pliku wygląda następująco:

$template NazwaSzablonu,"/sciezka/z/wykorzystaniem/tagow/np/%HOSTNAME%"

Użycie tak zdefiniowanego szablonu sprowadza się do użycia jego nazwy poprzedzonej znakiem ? zamiast nazwy konkretnego pliku, np:

*.* ?NazwaSzablonu

Tyle teorii, teraz jakiś działający przykład do przetestowania. Scenariusz jest następujący: kilka serwerów klienckich przesyła swoje logi do serwera centralnego. Serwer centralny zapisuje logi z poszczególnych hostów w osobnych katalogach o nazwach zgodnych z hostname klienta. Z logów odławiać będziemy zdarzenia z programu sshd, które będą trafiać do osobnego pliku w katalogu hosta.
Realizacja zadania sprowadzi się do kilku linijek, i obsłuży obecne i przyszłe hosty zdalnie logujące:

$template HostMessages,"/var/log/%hostname%/messages"
$template HostSshd,"/var/log/%hostname%/sshd"

:programname, isequal, "sshd"   ?HostSshd
:programname, isequal, "sshd"   ~

*.* ?HostMessages

Pierwsze dwie linijki definiują nam dynamiczne nazwy plików (a w zasadzie dynamiczne są katalogi, w których są pliki). Linijka trzecia przekierowuje logi z sshd do odpowiedniego pliku, podczas gdy czwarta "discarduje" je, aby nie trafiały już do pliku ogólnego. Ostatnia linijka kieruje pozostałe logi z hosta do pliku messages w katalogu zgodnym z nazwą hosta.
Voila, oto całość definicji, która równie dobrze sprawdza się dla 2 co i dla 200 hostów zdalnie logujących do serwera centralnego.

Jak pisałem na początku, temat filtrów rsyslog jest bardzo obszerny, a powyższy tekst ociera się o elementy, które okazały się przydatne w moim administratorskim bycie. Zainteresowanym osiągnięciem mistrzostwa w tej dziedzinie polecam dokumentację - zarówno systemową jak i  projektu ze strony rsyslog.