AppArmor
Po tej lekcji: kursant wie, czym AppArmor różni się od SELinuksa, sprawdza jego stan przez aa-status, czyta profil, przełącza go między trybami enforce i complain, znajduje odmowę w dzienniku i dopisuje własny wyjątek bez wyłączania ochrony.
Wstęp
Ubuntu, terminal, sudo tcpdump -i any -w /srv/zrzut.txt
Ubuntu, jesteś rootem, chcesz zapisać ruch sieciowy do pliku. A tcpdump na to:
tcpdump: /srv/zrzut.txt: Permission deniedRoot. Permission denied. To jak dyrektor, któremu portier nie wydaje kluczy do własnego gabinetu. Zmieniasz nazwę na /srv/zrzut.pcap i nagle działa. Jakby system miał alergię na rozszerzenie .txt.
Nie ma alergii. Ma AppArmora. I to, co wygląda na złośliwość, to bardzo sensowna zasada zapisana w jednym pliku. Dziś go przeczytamy.
Przepustka z listą pomieszczeń
W poprzedniej lekcji SELinux był ochroniarzem, który patrzy na kolory plakietek i naklejki na drzwiach. Wszystko w budynku ma naklejkę.
AppArmor robi to inaczej. Nie nakleja niczego na drzwi. Zamiast tego wybrani pracownicy dostają imienną przepustkę z listą pomieszczeń: „tcpdump może wejść do pokoju 12, czytać w archiwum, pisać tylko do teczek z napisem .pcap”. Ochroniarz sprawdza przepustkę i nazwę pokoju. Kto nie ma przepustki, chodzi tylko na zwykłych kluczach.
Ta przepustka to profil. A reguły mówią o ścieżkach, nie o etykietach. Stąd najważniejsza różnica w praktyce:
| SELinux | AppArmor | |
|---|---|---|
| Czego się trzyma | etykiet na plikach i procesach | ścieżek w profilu programu |
| Kogo pilnuje | cały system według polityki | tylko programy, które mają profil |
| Gdzie domyślnie | RHEL, Rocky, Alma, Fedora | Ubuntu, Debian |
mv z domowego folderu | psuje (stara naklejka) | nie ma znaczenia |
| Nowa ścieżka dla usługi | semanage fcontext + restorecon | dopisanie ścieżki do profilu |
AppArmor jest prostszy do czytania. Profil otwierasz w edytorze i od razu widzisz, co wolno. W SELinuksie regulamin ma tysiące reguł skompilowanych w binarny plik. Za to SELinux pilnuje dokładniej. Na rozmowie rekrutacyjnej to pytanie pada częściej niż „gdzie widzisz się za pięć lat”.
[RHEL] Na RHEL i pochodnych AppArmora po prostu nie ma. [Ubuntu] Na Ubuntu jest zainstalowany i włączony od pierwszego uruchomienia.
Kto ma przepustkę: aa-status
sudo aa-statusapparmor module is loaded.
117 profiles are loaded.
41 profiles are in enforce mode.
/usr/bin/man
tcpdump
...
4 profiles are in complain mode.
...
3 processes have profiles defined.
2 processes are in enforce mode.
/usr/sbin/rsyslogd (812)
...
0 processes are unconfined but have a profile defined.Liczby u Ciebie będą inne, ważny jest układ. Profile załadowane. Ile pilnuje naprawdę (enforce), a ile tylko notuje (complain). I które działające procesy są pod nadzorem. Ostatnia linijka jest podstępna: „procesy bez nadzoru, choć mają profil”. To programy uruchomione, zanim profil się załadował. Pomaga restart usługi.
W kontenerze albo na systemie bez AppArmora zobaczysz krótko:
apparmor not present.aa-status jest w pakiecie apparmor. Komendy aa-enforce, aa-complain, aa-genprof i aa-logprof są w osobnym pakiecie:
sudo apt install apparmor-utilsJak wygląda przepustka
Profile leżą w /etc/apparmor.d/. Nazwa pliku to zwykle ścieżka programu z kropkami zamiast ukośników: /usr/bin/tcpdump ma profil usr.bin.tcpdump. Otwórzmy go:
less /etc/apparmor.d/usr.bin.tcpdumpprofile tcpdump /usr/bin/tcpdump {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/user-tmp>
capability net_raw,
network raw,
network packet,
...
# for -F and -w
audit deny @{HOME}/.* mrwkl,
owner @{HOME}/** rw,
# for -r, -F and -w
/**.[pP][cC][aA][pP] rw,
/**.[pP][cC][aA][pP][nN][gG] rw,
/**.[cC][aA][pP] rw,
...
#include <local/usr.bin.tcpdump>
}Czytamy jak przepustkę:
profile tcpdump /usr/bin/tcpdump— przepustka nazywa się tcpdump i dostaje ją program z tej ścieżki.#include <abstractions/base>— gotowe zestawy uprawnień, których potrzebuje prawie każdy program: biblioteki,/dev/nulli tak dalej. Jak „standardowy pakiet socjalny”.capability net_raw— które supermoce roota wolno mu użyć. Tu: surowe gniazda sieciowe, bez tego nie podsłuchasz ruchu./**.[pP][cC][aA][pP] rw— czytaj i pisz pliki z końcówką.pcap, w dowolnym miejscu, w dowolnej wielkości liter.**to „w dowolnej głębokości folderów”.owner @{HOME}/** rw— we własnym folderze domowym wolno wszystko, ale tylko własne pliki.audit deny @{HOME}/.* mrwkl— ale ukrytych plików w domu nie ruszać. Bo tam są klucze SSH i ustawienia. Gdyby ktoś przejął tcpdump, mógłby nadpisać Ci.bashrc.
I mamy zagadkę z haka. /srv/zrzut.txt nie kończy się na .pcap, nie jest w domu i nie jest w /tmp (to daje abstractions/user-tmp). Na przepustce nie ma takiego pokoju. Root czy nie root: odmowa.
Literki uprawnień to: r czytanie, w pisanie, m mapowanie do pamięci jako kod, k blokady, l dowiązania, x uruchamianie, najczęściej jako ix, czyli „uruchom z tą samą przepustką”. Każda reguła kończy się przecinkiem. Zapamiętaj ten przecinek, wróci w typowym błędzie.
Tryby: enforce i complain
Profil może pracować w dwóch trybach. Brzmi znajomo, bo to prawie to samo, co w SELinuksie:
- enforce — pilnuje i blokuje. Odmowy trafiają do dziennika.
- complain — wpuszcza, ale zapisuje, co by zablokował. Tryb do nauki i szukania problemów.
Przełączanie:
sudo aa-complain /usr/bin/tcpdump
sudo aa-enforce /usr/bin/tcpdumpSetting /usr/bin/tcpdump to complain mode.
Setting /usr/bin/tcpdump to enforce mode.A co się naprawdę dzieje? Popatrz na pierwszą linijkę profilu po aa-complain:
grep '^profile' /etc/apparmor.d/usr.bin.tcpdumpprofile tcpdump /usr/bin/tcpdump flags=(complain) {Narzędzie po prostu dopisuje w pliku flags=(complain) i przeładowuje profil. aa-enforce to zdejmuje. Żadnej magii, edycja tekstu z przeładowaniem.
Jest też trzecie wyjście, awaryjne: wyłączenie jednego profilu.
sudo aa-disable /usr/bin/tcpdump
ls -l /etc/apparmor.d/disable/Disabling /usr/bin/tcpdump.
lrwxrwxrwx 1 root root 34 ... usr.bin.tcpdump -> /etc/apparmor.d/usr.bin.tcpdumpW folderze disable pojawia się dowiązanie, a profil jest wyrzucany z jądra. To jak zabranie przepustki jednemu pracownikowi, a nie zwolnienie całej ochrony. Ale i tak: do szukania problemu używaj complain, nie disable.
Gdzie są odmowy
AppArmor zapisuje odmowy w dzienniku jądra. Najszybciej:
sudo journalctl -k | grep DENIED
sudo dmesg | grep DENIEDWpis wygląda mniej więcej tak (rozbity na dwie linijki):
audit: type=1400 audit(1768214339.499:511): apparmor="DENIED" operation="mknod" class="file"
profile="tcpdump" name="/srv/zrzut.txt" pid=17786 comm="tcpdump" requested_mask="c" denied_mask="c" fsuid=0 ouid=0Czytamy jak mandat z poprzedniej lekcji:
apparmor="DENIED"— zablokowane. W trybie complain zobaczysz tuALLOWED.operation="mknod"— próba utworzenia pliku.profile="tcpdump"— która przepustka.name=— do jakiej ścieżki.requested_mask="c"— czego chciał:cjak create, utworzyć.
Jeśli masz zainstalowany auditd, te same wpisy lądują w /var/log/audit/audit.log. Bez niego w dzienniku systemd.
Dopisanie wyjątku: folder local
Chcesz, żeby tcpdump mógł zapisywać do /srv/zrzuty/? Nie edytuj głównego profilu. Przy aktualizacji pakietu może zostać nadpisany albo apt zacznie zadawać pytania. Popatrz na ostatnią linijkę profilu: #include <local/usr.bin.tcpdump>. To miejsce specjalnie na Twoje dopiski.
sudo mkdir -p /srv/zrzuty
echo '/srv/zrzuty/** rw,' | sudo tee -a /etc/apparmor.d/local/usr.bin.tcpdump
sudo apparmor_parser -r /etc/apparmor.d/usr.bin.tcpdump
sudo tcpdump -i any -c 10 -w /srv/zrzuty/test.txtapparmor_parser -r to replace: wczytaj profil na nowo do jądra. Bez tego zmiana w pliku nic nie robi. To jak wydrukowanie nowej przepustki i zostawienie jej w drukarce.
Jedno ograniczenie: reguły deny wygrywają z regułami pozwalającymi. Ukrytych plików w domu nie odblokujesz dopiskiem w local, bo profil ma na nie wyraźne deny. I dobrze.
Własny profil
Do własnych programów służą dwa pomocniki. sudo aa-genprof /usr/local/bin/raport.sh tworzy szkic profilu: uruchamiasz program w drugim terminalu, robisz wszystko, co program normalnie robi, a narzędzie pyta o każdą zauważoną akcję: pozwolić, zabronić, uogólnić. Później sudo aa-logprof czyta dziennik i proponuje dopiski do istniejących profili.
Mały ręczny profil wygląda tak:
abi <abi/4.0>,
include <tunables/global>
profile raport /usr/local/bin/raport.sh {
include <abstractions/base>
include <abstractions/bash>
/usr/local/bin/raport.sh r,
/usr/bin/bash ix,
/usr/bin/date ix,
/usr/bin/df ix,
/etc/hostname r,
/var/log/raport/ r,
/var/log/raport/** w,
}Zanim go załadujesz, sprawdź składnię bez ładowania do jądra:
sudo apparmor_parser -QTK /etc/apparmor.d/usr.local.bin.raport && echo OKOK-Q znaczy „tylko skompiluj, nie ładuj”. Potem apparmor_parser -r i najlepiej najpierw aa-complain, żeby przez kilka dni zebrać w dzienniku to, o czym zapomniałeś.
Jak to działa pod spodem
AppArmor to, tak jak SELinux, moduł bezpieczeństwa jądra (LSM). Plik tekstowy profilu czyta apparmor_parser, kompiluje go do postaci binarnej i wysyła do jądra. Przy starcie systemu robi to usługa apparmor.service dla wszystkich profili z /etc/apparmor.d.
Gdy jakiś proces uruchamia program, jądro patrzy na ścieżkę pliku. Pasuje do któregoś profilu? Nowy proces dostaje tę przepustkę na całe życie. Potem przy każdym otwarciu pliku, użyciu supermocy czy gniazda sieciowego jądro sprawdza najpierw zwykłe uprawnienia, potem przepustkę.
I tu jest słaby punkt podejścia „po ścieżkach”: ten sam plik pod inną nazwą to dla AppArmora inna rzecz. Dlatego profile pilnują też tworzenia dowiązań (l). SELinux z naklejkami tego problemu nie ma, ma za to problem z mv. Nie ma idealnego ochroniarza, są tylko różne rodzaje pecha.
Ściąga flag
| Komenda | Flaga | Co robi |
|---|---|---|
aa-status | stan: profile, tryby, procesy pod nadzorem | |
aa-enforce | /ścieżka/programu | profil w tryb enforce |
aa-complain | /ścieżka/programu | profil w tryb complain (dopisuje flags=(complain)) |
aa-disable | /ścieżka/programu | wyłącza jeden profil (dowiązanie w disable/) |
apparmor_parser | -r | przeładuj profil w jądrze |
apparmor_parser | -R | usuń profil z jądra |
apparmor_parser | -QTK | tylko sprawdź składnię, bez ładowania i cache |
aa-genprof | /ścieżka | interaktywnie buduje nowy profil |
aa-logprof | proponuje dopiski na podstawie dziennika | |
journalctl | -k | grep DENIED | odmowy w dzienniku jądra |
systemctl | reload apparmor | przeładuj wszystkie profile |
⚠ Typowy błąd
Zapomniany przecinek. Dopisujesz regułę, przeładowujesz i dostajesz:
AppArmor parser error for /etc/apparmor.d/usr.local.bin.raport in profile ... at line 13: missing an end of line character? (entry: /etc/hostname)Parser mówi „brakuje końca linijki”, ale chodzi o przecinek po /etc/hostname r. Każda reguła w profilu kończy się przecinkiem, nawet ostatnia przed klamrą. Gorzej, jeśli zmienisz profil i nie przeładujesz: plik mówi jedno, jądro pilnuje według starej wersji, a Ty od godziny szukasz błędu w miejscu, gdzie go już nie ma. Po każdej zmianie: apparmor_parser -r i aa-status.
✎ Zadanie
Na maszynie wirtualnej z Ubuntu:
- Sprawdź
aa-status: ile profili jest w trybie enforce, a ile w complain? - Spróbuj zapisać
sudo tcpdump -i any -c 5 -w /srv/test.txti znajdź odmowę w dzienniku jądra. - Przełącz tcpdump w complain, ponów zapis, znajdź w dzienniku wpis
ALLOWEDi wróć do enforce. - Pozwól tcpdumpowi zapisywać do
/srv/zrzuty/przez plik w/etc/apparmor.d/local/i sprawdź, że działa.
Pokaż rozwiązanie
Ubuntu, AppArmor. Najpierw spis:
sudo aa-status | grep -E 'profiles are in (enforce|complain) mode'U mnie kilkadziesiąt w enforce i kilka w complain. Liczby zależą od tego, co masz zainstalowane, więc nie porównuj się z sąsiadem. Potem odmowa:
sudo tcpdump -i any -c 5 -w /srv/test.txt
sudo journalctl -k | grep DENIED | tail -1W dzienniku: apparmor="DENIED", profile="tcpdump", name="/srv/test.txt". Teraz tryb nauki:
sudo aa-complain /usr/bin/tcpdump
sudo tcpdump -i any -c 5 -w /srv/test.txt
sudo journalctl -k | grep ALLOWED | tail -1
sudo aa-enforce /usr/bin/tcpdumpZapis przechodzi, a w dzienniku ten sam wpis, tylko z apparmor="ALLOWED". Ochroniarz przepuścił, ale zapisał w zeszycie. I na koniec wyjątek:
sudo mkdir -p /srv/zrzuty
echo '/srv/zrzuty/** rw,' | sudo tee -a /etc/apparmor.d/local/usr.bin.tcpdump
sudo apparmor_parser -r /etc/apparmor.d/usr.bin.tcpdump
sudo tcpdump -i any -c 5 -w /srv/zrzuty/test.txtJeśli zapomniałeś o aa-enforce po teście, to tcpdump do dziś chodzi bez nadzoru. Taki strażnik, który na próbę zostawił otwarte drzwi i poszedł na obiad. Sprawdź aa-status.
Co dalej
Mamy dwóch ochroniarzy. Ale ochroniarz nie pomoże, jeśli tylne drzwi są otwarte, a hasło do SSH to „admin123”. W następnej lekcji robimy przegląd całego budynku: utwardzanie serwera, fail2ban, auditd i automatyczni audytorzy, którzy wystawią Twojemu serwerowi ocenę.