Linux

Linux Hardening Jeden pakiet, siedem strażników. Jak Linux podejmuje decyzję o bezpieczeństwie

Linux Hardening: Jeden pakiet, siedem strażników. Jak Linux podejmuje decyzję o bezpieczeństwie

Administratorzy często mówią o bezpieczeństwie Linuksa tak, jakby składało się z pojedynczych narzędzi. Jest firewall. Jest AppArmor. Jest Docker. Jest Fail2Ban. Każde z nich dostaje własny poradnik i własną konfigurację. Problem w tym, że prawdziwy Linux nie działa w ten sposób.

Kiedy pojedynczy pakiet trafia do serwera, nie przechodzi przez jedną bramkę bezpieczeństwa. Przechodzi przez całą serię decyzji podejmowanych w różnych miejscach jądra, przestrzeni użytkownika i usług systemowych. Większość administratorów widzi jedynie efekt końcowy: połączenie zostało zaakceptowane albo odrzucone. Znacznie ciekawsze pytanie brzmi: ile mechanizmów zdążyło podjąć decyzję, zanim aplikacja w ogóle zobaczyła pierwszy bajt danych?

Prześledźmy drogę jednego pakietu.

Scena pierwsza: ktoś puka do drzwi

Wyobraźmy sobie prosty serwer.

  • Ubuntu Server
  • SSH
  • Nginx
  • Docker
  • AppArmor
  • UFW
  • systemd

Z Internetu nadchodzi połączenie HTTPS.

Na pierwszy rzut oka wygląda to banalnie.

Internet
    │
    ▼
Serwer

W rzeczywistości właśnie rozpoczęła się podróż przez kilka niezależnych mechanizmów bezpieczeństwa.

Strażnik pierwszy: karta sieciowa

Pakiet trafia najpierw do interfejsu sieciowego.

Dla administratora to zwykłe eth0.

Dla kernela to sterownik urządzenia.

Już tutaj mogą działać mechanizmy takie jak:

  • XDP,
  • eBPF,
  • sprzętowe filtry NIC.

Jeżeli administrator wykorzystuje XDP, część pakietów może zostać odrzucona jeszcze zanim kernel zacznie wykonywać większość swojej pracy.

To trochę jak ochrona przed wejściem do budynku.

Nie trzeba wpuszczać każdego do recepcji.

Strażnik drugi: Netfilter

Jeżeli pakiet przejdzie dalej, trafia do Netfilter.

To właśnie tutaj działają:

  • nftables,
  • iptables,
  • UFW.

Schemat wygląda następująco.

Tutaj zapada pierwsza świadoma decyzja administratora.

Reguła może powiedzieć:

ALLOW TCP 443

albo:

DROP TCP 22

To jednak dopiero początek.

Strażnik trzeci: socket

Pakiet został zaakceptowany.

Jeszcze nie oznacza to, że aplikacja go otrzyma.

Kernel tworzy kontekst połączenia.

Przypisuje:

  • adres źródłowy,
  • port,
  • stan połączenia,
  • odpowiedni socket.

To właśnie dlatego polecenie:

Bash

ss -tulpn

pokazuje znacznie więcej niż listę otwartych portów.

Pokazuje miejsca, do których kernel może skierować ruch.

Strażnik czwarty: capabilities

Tutaj zaczyna się coś, czego wielu administratorów praktycznie nie używa.

Linux od dawna odchodzi od prostego modelu:

root
albo
nie-root

Pojawiły się capabilities.

Przykład.

Serwer WWW potrzebuje nasłuchiwać na porcie 80.

Nie musi jednak posiadać wszystkich uprawnień administratora.

Wystarczy:

CAP_NET_BIND_SERVICE

To ogromna zmiana filozofii.

Zamiast dawać pełną władzę, dajemy tylko konkretną możliwość.

Strażnik piąty: namespaces

Tutaj zaczyna się magia współczesnego Linuksa.

Wyobraźmy sobie dwa kontenery.

Każdy uruchamia proces o numerze PID 1.

Brzmi niemożliwie.

A jednak działa.

Dlaczego?

Bo każdy żyje w innym namespace.

Host
 ├── PID 2314
 ├── PID 8821
 │
 ├── Namespace A
 │      └── PID 1
 │
 └── Namespace B
        └── PID 1

To właśnie namespaces sprawiają, że kontenery mogą wyglądać jak osobne systemy.

Nie są pełnymi maszynami wirtualnymi.

Ale dostają własny punkt widzenia na świat.

Strażnik szósty: AppArmor lub SELinux

Dopiero teraz wchodzimy do mechanizmów MAC.

Wyobraźmy sobie, że aplikacja została przejęta.

Bez dodatkowych ograniczeń mogłaby próbować czytać kolejne katalogi.

AppArmor może powiedzieć:

Możesz czytać:
/var/www/

Nie możesz czytać:
/home/admin/

SELinux podejdzie do tego inaczej – przez konteksty bezpieczeństwa.

Cel pozostaje jednak podobny.

Proces nie powinien robić wszystkiego tylko dlatego, że udało się go uruchomić.

 

Strażnik siódmy: seccomp

To mój ulubiony mechanizm.

Dlaczego?

Bo działa na poziomie wywołań systemowych.

Wyobraźmy sobie proces.

Chce wykonać:

open()

Kernel pyta:

Czy ta operacja jest dozwolona?

Jeżeli profil seccomp odpowie:

DENY

proces dostaje odmowę.

To niezwykle precyzyjna kontrola.

Nie blokujemy programu.

Blokujemy konkretną czynność.

A gdzie w tym wszystkim jest systemd?

Wiele osób traktuje systemd wyłącznie jako menedżera usług.

To ogromne niedocenienie jego możliwości.

Nowoczesny systemd potrafi tworzyć własne ograniczenia.

Przykładowo:

INI

ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
NoNewPrivileges=yes

Nagle usługa otrzymuje własny świat.

Nie przez kontener.

Nie przez VM.

Przez odpowiednią konfigurację jednostki.

To jeden z najbardziej niedocenianych elementów współczesnego hardeningu.

Jeden proces, wiele granic

Wyobraźmy sobie teraz prawdziwy scenariusz.

Napastnik wykorzystuje podatność RCE w aplikacji.

Proces startuje jako użytkownik www-data.

Od tej chwili kolejne mechanizmy zaczynają ograniczać jego możliwości.

Najciekawsze jest to, że żaden z tych mechanizmów samodzielnie nie daje pełnej ochrony.

Razem tworzą coś znacznie silniejszego.

Dlaczego to podejście jest skuteczniejsze niż „jedno narzędzie”

W bezpieczeństwie istnieje zasada, którą bardzo lubię.

Nie zakładaj, że jedna warstwa będzie działała zawsze.

Załóż, że każda kiedyś zawiedzie.

Jeżeli firewall przepuści legalny ruch…

AppArmor nadal działa.

Jeżeli aplikacja zostanie przejęta…

seccomp nadal działa.

Jeżeli proces potrzebuje tylko jednego capability…

nie dostaje pozostałych.

To właśnie jest Defense in Depth.

Nie teoria.

Codzienna praktyka współczesnego Linuksa.

Eksperyment, który warto wykonać

Na własnym serwerze można bardzo łatwo zobaczyć, jak te warstwy współpracują.

Najpierw sprawdź otwarte porty.

Bash

ss -tulpn

Potem capabilities procesu.

Bash

getcap -r /usr/sbin

Następnie status AppArmor.

Bash

apparmor_status

Na końcu aktywne namespace.

Bash

lsns

Nagle okazuje się, że system, który wydawał się „po prostu Linuksem”, składa się z wielu niezależnych granic bezpieczeństwa.

Największa zmiana ostatnich lat

Jeszcze dziesięć lat temu wielu administratorów koncentrowało się głównie na firewallu.

Dzisiaj granice bezpieczeństwa przesuwają się coraz bliżej samego jądra.

  • eBPF obserwuje zachowanie systemu.
  • seccomp filtruje syscalle.
  • AppArmor ogranicza procesy.
  • Capabilities rozbijają władzę roota.
  • Namespaces izolują środowiska.
  • systemd tworzy piaskownice dla usług.

To nie jest zbiór przypadkowych technologii.

To ewolucja jednego pomysłu.

Linux coraz rzadziej pyta:

„Czy użytkownik jest rootem?”

Coraz częściej pyta:

„Czy ten konkretny proces naprawdę potrzebuje wykonać właśnie tę operację?”

I właśnie w tej zmianie kryje się największa siła współczesnego hardeningu.

Polecane wpisy
Najlepsze programy do ochrony antywirusowej – ranking i porównanie
Najlepsze programy do ochrony antywirusowej – ranking i porównanie

Najlepsze programy do ochrony antywirusowej – ranking i porównanie W dzisiejszych czasach ochrona antywirusowa jest niezbędnym elementem bezpieczeństwa zarówno dla Czytaj dalej

Hacked Detect: Wazność cyberbezpieczeństwa i wykrywania włamań
Hacked Detect: Wazność cyberbezpieczeństwa i wykrywania włamań

W dzisiejszej cyfrowej erze cyberbezpieczeństwo stało się kluczowym zagadnieniem dla jednostek, firm i organizacji o różnej skali działania. Ciągłe zagrożenie Czytaj dalej

Marek "Netbe" Lampart Inżynier informatyki Marek Lampart to doświadczony inżynier informatyki z ponad 25-letnim stażem w zawodzie. Specjalizuje się w systemach Windows i Linux, bezpieczeństwie IT, cyberbezpieczeństwie, administracji serwerami oraz diagnostyce i optymalizacji systemów. Na netbe.pl publikuje praktyczne poradniki, analizy i instrukcje krok po kroku, pomagając administratorom, specjalistom IT oraz zaawansowanym użytkownikom rozwiązywać realne problemy techniczne.