Przejdź do treści
Lekcja 84 z 117

Kurs › Moduł 9 › Lekcja 84

Utwardzanie serwera

⏱ ok. 11 min czytania· moduł 9: Użytkownicy i bezpieczeństwo

Po tej lekcji: kursant umie przejść serwer po liście utwardzania: aktualizacje, zbędne usługi, SSH tylko na klucze, fail2ban, auditd, a potem wystawić serwerowi ocenę narzędziami lynis, OpenSCAP i AIDE.

Wstęp

świeży serwer w chmurze, journalctl -u ssh przewija się bez końca: Invalid user admin, Invalid user oracle, Failed password for root

Stawiasz nowy serwer z publicznym adresem. Idziesz zrobić kawę. Wracasz, zaglądasz do dziennika SSH, a tam już ktoś próbuje: admin, oracle, root, test, ubuntu. Nikt jeszcze nie zna adresu Twojej strony, ale boty znają. One nie szukają Ciebie. One pukają do każdych drzwi w internecie, cały czas, od lat.

Na to jest jedna odpowiedź: zamknąć wszystko, co niepotrzebne, a to, co potrzebne, zamknąć porządnie. To się nazywa utwardzanie, po angielsku hardening. Dziś przejdziemy całą listę, a na końcu zawołamy automatycznych audytorów, którzy wystawią serwerowi świadectwo.

Zamykanie domu przed wyjazdem

Wyjeżdżasz na urlop. Zamykasz drzwi, okna, wyłączasz żelazko, zakręcasz wodę, prosisz sąsiada, żeby zerkał. Utwardzanie serwera to dokładnie to samo, tylko żelazek jest więcej i niektóre są niewidoczne.

Fachowo: zmniejszasz powierzchnię ataku. Każdy program, który działa, każdy otwarty port, każde konto z hasłem to kolejne okno, przez które da się wejść. Nie da się zrobić serwera, w który nie da się włamać. Da się zrobić taki, przy którym bot pukający do milionów drzwi wzruszy ramionami i pójdzie do sąsiada.

Krok 1: aktualizacje

Większość włamań nie wymaga geniusza. Wymaga dziury, która ma łatkę od miesiąca, tylko nikt jej nie zainstalował. Z lekcji 65 znasz już unattended-upgrades:

# [Ubuntu]
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

[RHEL] Na Red Hacie to samo robi dnf-automatic:

sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic-install.timer

Timer dnf-automatic-install pobiera i od razu instaluje. Są też delikatniejsze wersje: dnf-automatic-download.timer tylko pobiera, dnf-automatic-notifyonly.timer tylko powiadamia. Ustawienia leżą w /etc/dnf/automatic.conf.

Pamiętaj: zaktualizowana biblioteka w pamięci starego procesu to dalej stara biblioteka. Po aktualizacji sprawdź, co trzeba zrestartować: needrestart na Ubuntu, dnf needs-restarting na RHEL.

Krok 2: wyłącz to, czego nie używasz

Czego nie ma, tego nie da się zhakować. Lista działających usług i otwartych portów:

systemctl list-units --type=service --state=running
sudo ss -tulpn

Serwer WWW z drukarką CUPS, serwerem pocztowym i Avahi, które rozgłasza w sieci „hej, jestem tu!”? To jak trzymanie w biurze rachunkowym automatu do waty cukrowej. Może i miłe, ale po co.

sudo systemctl disable --now cups.service
sudo systemctl mask cups.service

disable --now zatrzymuje i wyłącza autostart. mask idzie dalej: zakleja usługę tak, że nie uruchomi jej nawet inna usługa, która by jej potrzebowała. Zanim coś wyłączysz, sprawdź, czy nikt tego nie używa. Wyłączenie sshd na zdalnym serwerze to bardzo skuteczne utwardzenie. Także przed Tobą.

Krok 3: SSH tylko na klucze

Klucze SSH znasz z lekcji 76: kłódka na serwerze, kluczyk w kieszeni. Teraz wyłączamy hasła. Bot może zgadywać hasła do końca świata, ale klucza nie zgadnie.

⚠️ Zanim zaczniesz: miej otwartą drugą sesję SSH i sprawdź, że logowanie kluczem działa. Jedna pomyłka w sshd_config i odcinasz sobie drogę. Na pierwszy raz rób to na maszynie wirtualnej, gdzie masz konsolę.

Nie edytujemy głównego pliku. Robimy dopisek w folderze sshd_config.d:

sudo tee /etc/ssh/sshd_config.d/01-utwardzanie.conf <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo sshd -t && echo OK
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin)'
OK
permitrootlogin no
passwordauthentication no

sshd -t sprawdza składnię. sshd -T to jeszcze lepsza rzecz: pokazuje ustawienia, które serwer naprawdę zastosuje po przeczytaniu wszystkich plików. Dopiero gdy obie są w porządku:

sudo systemctl reload ssh      # [Ubuntu]
sudo systemctl reload sshd     # [RHEL]

I z drugiego okna próbujesz się zalogować, zanim zamkniesz pierwsze. Dlaczego plik zaczyna się od 01? To nie przypadek. Wyjaśnię w typowym błędzie.

Krok 4: fail2ban, bramkarz z pamięcią

Nawet z kluczami boty będą pukać i zaśmiecać dziennik. fail2ban to bramkarz, który czyta dziennik i zapamiętuje twarze. Kto pomyli się pięć razy w dziesięć minut, dostaje zakaz wstępu na godzinę. Zakaz wpisuje do zapory, o której było w lekcji 73.

sudo apt install fail2ban      # [Ubuntu]
sudo dnf install epel-release && sudo dnf install fail2ban   # [RHEL], pakiet jest w EPEL

Nie edytuj jail.conf, bo nadpisze go aktualizacja. Twój plik to jail.local:

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 192.0.2.10

[sshd]
enabled = true

ignoreip to lista gości VIP. Wpisz tam adres, z którego sam się łączysz. Inaczej pierwszego dnia zbanujesz sam siebie, a to najbardziej upokarzający sposób na utratę dostępu.

sudo fail2ban-client -t
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Po kilku nieudanych próbach z adresu testowego:

Status for the jail: sshd
|- Filter
|  |- Currently failed:	1
|  |- Total failed:	4
`- Actions
   |- Currently banned:	1
   |- Total banned:	1
   `- Banned IP list:	203.0.113.50

Zdjęcie bana:

sudo fail2ban-client set sshd unbanip 203.0.113.50

A jak sprawdzić, czy bramkarz w ogóle rozpoznaje twarze w Twoim dzienniku? Jest do tego tester:

sudo fail2ban-regex /var/log/auth.log sshd
Lines: 5 lines, 1 ignored, 4 matched, 0 missed

Cztery linijki z nieudanym logowaniem złapane, jedna (udane logowanie kluczem) zignorowana. Tak ma być.

Krok 5: auditd, czarna skrzynka

Dziennik mówi, co robiły usługi. A kto w nocy zmienił /etc/passwd? Od tego jest auditd: czarna skrzynka samolotu. Jądro samo zapisuje wybrane zdarzenia, a demon auditd zrzuca je do /var/log/audit/audit.log. Ten sam plik, z którego SELinux czyta odmowy.

sudo apt install auditd        # [Ubuntu]; na RHEL jest od instalacji
sudo auditctl -w /etc/passwd -p wa -k zmiany_kont
sudo auditctl -l

-w to obserwowany plik, -p wa to rodzaje dostępu: w zapis, a zmiana atrybutów (są jeszcze r odczyt i x uruchomienie), -k to etykieta, po której potem szukasz. Ktoś zmienia plik, a Ty:

sudo ausearch -k zmiany_kont -i
sudo aureport -k --summary
type=SYSCALL msg=audit(11/03/26 16:41:11.354:4) : arch=x86_64 syscall=openat success=yes ... uid=root ... comm=zsh exe=/usr/bin/zsh ... key=zmiany_kont

Key Summary Report
===========================
total  key
===========================
2  zmiany_kont

W pełnym wpisie są też auid, czyli kto się pierwotnie zalogował, nawet jeśli potem zrobił sudo, i exe, czyli jakim programem. -i zamienia numery na nazwy.

Reguła z auditctl znika po restarcie. Na stałe wpisujesz ją do pliku w /etc/audit/rules.d/:

echo '-w /etc/passwd -p wa -k zmiany_kont' | sudo tee /etc/audit/rules.d/konta.rules
sudo augenrules --load

[RHEL] Ciekawostka: Red Hat w dokumentacji pisze, że z demonem auditd należy rozmawiać komendą service (service auditd restart), a nie systemctl. Wtedy w dzienniku zapisze się właściwy auid. Jeden z niewielu przypadków, kiedy stara komenda jest tą poprawną.

Krok 6: audytorzy

Zrobiłeś listę. Ale skąd wiesz, czego nie zrobiłeś? Pora zawołać inspektorów.

lynis to inspektor budowlany, który obchodzi budynek z latarką i notesem. Nic nie zmienia, tylko ocenia.

sudo apt install lynis         # [Ubuntu]; [RHEL] z EPEL
sudo lynis audit system --quick

Na końcu dostajesz świadectwo:

  Warnings (2):
  ----------------------------
  ! No AIDE database was found, needed for AIDE functionality [FINT-4316]

  Suggestions (58):
  ----------------------------
  * Consider hardening SSH configuration [SSH-7408]
    - Details  : MaxAuthTries (set 6 to 3)
  * Default umask in /etc/login.defs could be more strict like 027 [AUTH-9328]
  ...
  Hardening index : 63 [############        ]
  Tests performed : 285

Indeks utwardzenia 63 na 100. Jak świadectwo z czwórką: nie wstyd, ale jest nad czym pracować. Każda sugestia ma kod w nawiasie. sudo lynis show details SSH-7408 mówi, co sprawdził. Szczegóły leżą w /var/log/lynis.log. Nie goniń setki. Część sugestii nie pasuje do Twojego serwera i to jest normalne.

OpenSCAP to audytor z urzędu. Nie ocenia „na oko”, tylko porównuje serwer z oficjalną normą: CIS, PCI-DSS dla płatności kartami, STIG amerykańskiej armii. W firmach, które przechodzą audyty, to nie hobby, tylko obowiązek.

# [RHEL]
sudo dnf install openscap-scanner scap-security-guide
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel10-ds.xml
sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis \
  --report raport.html /usr/share/xml/scap/ssg/content/ssg-rhel10-ds.xml

Na RHEL 9 plik nazywa się ssg-rhel9-ds.xml. Wynik to strona HTML z listą reguł: zielone pass, czerwone fail, z opisem, dlaczego i jak naprawić. Jest też flaga --remediate, która naprawia sama. Na produkcji nie używaj jej bez czytania, bo profil STIG potrafi przykręcić serwer tak, że przestanie robić cokolwiek, w tym to, za co mu płacą.

[Ubuntu] Na Ubuntu 24.04 pakiet openscap-scanner jest, ale treści w paczce ssg-debderived kończą się na Ubuntu 22.04:

$ oscap info /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml
		Profiles:
			Title: CIS Ubuntu 22.04 Level 1 Server Benchmark
				Id: xccdf_org.ssgproject.content_profile_cis_level1_server
			...

Dla nowszych wersji Canonical ma własne narzędzie USG, Ubuntu Security Guide, dostępne dla subskrybentów Ubuntu Pro.

AIDE to fotograf. Robi zdjęcie ważnych plików systemu: rozmiary, uprawnienia, właściciele, sumy kontrolne. Później robi drugie zdjęcie i pokazuje różnice. Jeśli ktoś podmienił /usr/bin/ls na wersję z niespodzianką, AIDE to zobaczy.

# [RHEL]
sudo dnf install aide
sudo aide --init
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
sudo aide --check

# [Ubuntu]
sudo apt install aide
sudo aideinit -y -f
sudo aide -c /etc/aide/aide.conf --check

Pierwsze zdjęcie zapisuje się jako .new i trzeba je przemianować. To celowe: masz zatwierdzić, że ten stan jest tym dobrym. Na Ubuntu aideinit robi to za Ciebie. Po zmianie pliku:

AIDE found differences between database and filesystem!!

Summary:
  Total number of entries:	3
  Added entries:		1
  Removed entries:		0
  Changed entries:		1
...
File: /srv/test/konfig.conf
 Size      : 16                               | 31
 SHA256    : PkyPwmGrrsmC/U+q9Vc7iEb/v/BgbeaN | b7dRrpaiBtDPuzrneSxjeWQG1b+UhLuz

Po planowanej zmianie, na przykład aktualizacji, robisz aide --update i znowu przemianowujesz bazę. A samą bazę najlepiej trzymaj poza serwerem. Fotograf, który trzyma zdjęcia w domu włamywacza, jest mało przydatny.

Jak to działa pod spodem

fail2ban to program w Pythonie, który czyta dziennik linijka po linijce i przykłada do każdej wyrażenia regularne z filter.d/. Wyciąga z dopasowania adres IP i liczy trafienia w oknie findtime. Po przekroczeniu maxretry uruchamia akcję z action.d/. Na Ubuntu 24.04 to nftables. W zaporze pojawia się tabela f2b-table z zestawem zbanowanych adresów:

table inet f2b-table {
	set addr-set-sshd {
		type ipv4_addr
		elements = { 203.0.113.50 }

auditd działa niżej. To jądro ma podsystem audytu, który przy wywołaniach systemowych sprawdza reguły i generuje zdarzenia. Demon tylko je odbiera i zapisuje. Dlatego audytu nie oszukasz, zmieniając plik innym programem: jądro widzi każde openat na obserwowanym pliku.

AIDE liczy dla każdego pliku wybrane atrybuty i skróty kryptograficzne i zapisuje je w skompresowanej bazie. Przy sprawdzaniu liczy wszystko od nowa i porównuje. Czym jest taki skrót i czemu zmiana jednej litery zmienia go całkowicie, zobaczysz w następnej lekcji.

Ściąga flag

KomendaFlagaCo robi
systemctldisable --now / maskwyłącza usługę / zakleja ją całkiem
sshd-tsprawdza składnię konfiguracji
sshd-Tpokazuje ustawienia, które naprawdę obowiązują
fail2ban-clientstatus sshdstan więzienia, lista banów
fail2ban-clientset sshd unbanip IPzdejmuje bana
fail2ban-client-ttest konfiguracji
fail2ban-regexPLIK FILTRsprawdza, czy filtr łapie linijki dziennika
auditctl-w PLIK -p wa -k KLUCZobserwuj plik
auditctl-l / -Wlista reguł / usuń obserwację
augenrules--loadwczytuje reguły z /etc/audit/rules.d/
ausearch-k KLUCZ -izdarzenia z etykietą, po ludzku
aureport-k --summarypodsumowanie wg etykiet
lynisaudit system --quickaudyt bez pauz
oscap xccdf eval--profile ID --report PLIKaudyt wg normy z raportem HTML
aide--init / --check / --updatezdjęcie / porównanie / nowe zdjęcie

⚠ Typowy błąd

„Wpisałem PasswordAuthentication no, zrestartowałem SSH, a serwer dalej pyta o hasło.”

SSH ma nietypową zasadę: wygrywa pierwsza znaleziona wartość, a nie ostatnia. Pliki z sshd_config.d są czytane alfabetycznie, a na Ubuntu Server 24.04, zarówno z instalatora ISO, jak i w chmurze, często leży tam już wygenerowany przez cloud-init plik 50-cloud-init.conf z PasswordAuthentication yes. Jeśli swój plik nazwiesz 99-utwardzanie.conf, przegra. Sprawdziłem:

# pliki: 50-cloud-init.conf (yes) i 99-utwardzanie.conf (no)
$ sudo sshd -T | grep passwordauthentication
passwordauthentication yes

# po zmianie nazwy na 01-utwardzanie.conf
$ sudo sshd -T | grep passwordauthentication
passwordauthentication no

Dlatego nazwa zaczyna się od 01, a po każdej zmianie patrzysz w sshd -T, nie w plik. I drugi klasyk: literówka w opcji.

/etc/ssh/sshd_config.d/01-utwardzanie.conf line 4: unsupported option "nie".

Napisane po polsku PermitRootLogin nie. SSH po polsku nie mówi. sshd -t złapie to przed restartem. Restart bez testu może zostawić Cię przed zamkniętymi drzwiami.

✎ Zadanie

Na maszynie wirtualnej (miej konsolę albo drugą sesję SSH):

  1. Wyłącz logowanie hasłem i roota przez plik w sshd_config.d. Udowodnij komendą sshd -T, że działa.
  2. Zainstaluj fail2ban z jail.local. Z drugiej maszyny spróbuj pięć razy zalogować się jako nieistniejący użytkownik. Pokaż fail2ban-client status sshd z banem, a potem zdejmij bana.
  3. Załóż obserwację auditd na /etc/passwd na stałe, dodaj użytkownika i znajdź to zdarzenie przez ausearch -k.
  4. Uruchom lynis audit system --quick, zapisz indeks utwardzenia, popraw dwie sugestie i sprawdź, czy indeks wzrósł.
Pokaż rozwiązanie

Cztery części, jedziemy po kolei. SSH:

sudo tee /etc/ssh/sshd_config.d/01-utwardzanie.conf <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo sshd -t && sudo systemctl reload ssh
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin)'
permitrootlogin no
passwordauthentication no

fail2ban: jail.local z lekcji, a z drugiej maszyny pięć razy ssh nieistnieje@serwer. Nawet przy wyłączonych hasłach w dzienniku lądują linijki Invalid user nieistnieje from ..., a filtr sshd je łapie. Potem:

sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 192.168.122.20

Jeśli nie dostałeś bana, sprawdź, czy adres drugiej maszyny nie siedzi w ignoreip. Zabezpieczyłeś się przed sobą tak skutecznie, że teraz nie możesz się zaatakować.

auditd na stałe:

echo '-w /etc/passwd -p wa -k zmiany_kont' | sudo tee /etc/audit/rules.d/konta.rules
sudo augenrules --load
sudo useradd testowy
sudo ausearch -k zmiany_kont -i | tail -5

W wyniku comm=useradd, exe=/usr/sbin/useradd i auid z Twoim loginem, nawet jeśli robiłeś to przez sudo. I lynis: przed poprawkami na mojej maszynie testowej indeks wyszedł 63. Dwie najprostsze sugestie to zwykle instalacja pakietu (np. needrestart albo apt-show-versions) i ostrzejszy UMASK 027 w /etc/login.defs. Po nich indeks rośnie o kilka punktów. Nie licz na skok do setki. To świadectwo, nie loteria.

Co dalej

Zamknęliśmy drzwi. Ale przez internet i tak trzeba rozmawiać, a każdy po drodze może podsłuchiwać. W następnej lekcji: jak działa kłódka w przeglądarce, certyfikaty, openssl, certbot, szyfrowanie plików gpg i sumy kontrolne, które powiedzą, czy ktoś grzebał w pliku.