Utwardzanie serwera
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.timerTimer 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 -tulpnSerwer 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.servicedisable --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 nosshd -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 EPELNie 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 = trueignoreip 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 sshdPo 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.50Zdjęcie bana:
sudo fail2ban-client set sshd unbanip 203.0.113.50A jak sprawdzić, czy bramkarz w ogóle rozpoznaje twarze w Twoim dzienniku? Jest do tego tester:
sudo fail2ban-regex /var/log/auth.log sshdLines: 5 lines, 1 ignored, 4 matched, 0 missedCztery 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 --summarytype=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_kontW 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 --quickNa 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 : 285Indeks 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.xmlNa 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 --checkPierwsze 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+UhLuzPo 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
| Komenda | Flaga | Co robi |
|---|---|---|
systemctl | disable --now / mask | wyłącza usługę / zakleja ją całkiem |
sshd | -t | sprawdza składnię konfiguracji |
sshd | -T | pokazuje ustawienia, które naprawdę obowiązują |
fail2ban-client | status sshd | stan więzienia, lista banów |
fail2ban-client | set sshd unbanip IP | zdejmuje bana |
fail2ban-client | -t | test konfiguracji |
fail2ban-regex | PLIK FILTR | sprawdza, czy filtr łapie linijki dziennika |
auditctl | -w PLIK -p wa -k KLUCZ | obserwuj plik |
auditctl | -l / -W | lista reguł / usuń obserwację |
augenrules | --load | wczytuje reguły z /etc/audit/rules.d/ |
ausearch | -k KLUCZ -i | zdarzenia z etykietą, po ludzku |
aureport | -k --summary | podsumowanie wg etykiet |
lynis | audit system --quick | audyt bez pauz |
oscap xccdf eval | --profile ID --report PLIK | audyt wg normy z raportem HTML |
aide | --init / --check / --update | zdję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 noDlatego 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):
- Wyłącz logowanie hasłem i roota przez plik w
sshd_config.d. Udowodnij komendąsshd -T, że działa. - Zainstaluj fail2ban z
jail.local. Z drugiej maszyny spróbuj pięć razy zalogować się jako nieistniejący użytkownik. Pokażfail2ban-client status sshdz banem, a potem zdejmij bana. - Załóż obserwację auditd na
/etc/passwdna stałe, dodaj użytkownika i znajdź to zdarzenie przezausearch -k. - 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 nofail2ban: 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.20Jeś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 -5W 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.