Chrootowany Unbound – lokalny resolver DNS trochę bezpieczniej

Na początku tego artykułu omówię czym jest i do czego służy Unbound. Jest to lekki, szybki i bezpieczny resolver DNS (Domain Name System) o otwartym kodzie źródłowym, stworzony głównie do lokalnego rozwiązywania nazw domen. Jest szeroko wykorzystywany jako lokalny serwer DNS, zarówno w środowiskach domowych, jak i w organizacjach, zapewniając prywatność, wydajność oraz kontrolę nad […]

Lut 4, 2025 - 04:46
 0
Chrootowany Unbound – lokalny resolver DNS trochę bezpieczniej

Na początku tego artykułu omówię czym jest i do czego służy Unbound. Jest to lekki, szybki i bezpieczny resolver DNS (Domain Name System) o otwartym kodzie źródłowym, stworzony głównie do lokalnego rozwiązywania nazw domen. Jest szeroko wykorzystywany jako lokalny serwer DNS, zarówno w środowiskach domowych, jak i w organizacjach, zapewniając prywatność, wydajność oraz kontrolę nad procesem rozwiązywania nazw domen. Przetwarza on zapytania DNS, łącząc się bezpośrednio z serwerami DNS w hierarchii od root (serwery stref głównych) aż po serwery domen docelowych. Dzięki temu eliminuje konieczność korzystania z zewnętrznych serwerów cache DNS. Obsługuje szyfrowanie zapytań DNS za pomocą DNS-over-TLS (DoT) i DNS-over-HTTPS (DoH), co chroni przed podsłuchiwaniem i modyfikowaniem zapytań DNS przez osoby trzecie.

Unbound utrzymuje lokalną pamięć podręczną (cache) zapytań DNS, co znacznie przyspiesza odpowiedzi na często powtarzające się zapytania. Odpytujemy bowiem serwer lokalny, nie zdalny. Unbound jest dodatkowo zoptymalizowany do obsługi dużej liczby równoczesnych zapytań i skalowalny w różnych środowiskach. W kontekście bezpieczeństwa co jest tu również kluczowe Unbound obsługuje DNSSEC (DNS Security Extensions), co zapewnia weryfikację autentyczności i integralności odpowiedzi DNS. Jest odporny na różne ataki, takie jak ataki cache poisoning, które mogą zmienić kierunek ruchu internetowego na złośliwe serwery.

Wiemy już czym jest i do czego służy, w skrócie przypomnę tylko czym jest chroot i jakie ma znaczenie w kontekście lokalnego resolvera. Chrootowanie (ang. change root) to mechanizm w systemach operacyjnych Linux, który pozwala uruchomić aplikację w tzw. „chroot jail”, czyli w izolowanym środowisku plikowym. W praktyce oznacza to, że aplikacja widzi jako swój „root” (root directory) jedynie wybrany katalog, a nie pełną strukturę systemu plików. Dzięki temu ograniczamy dostęp aplikacji do zasobów systemowych, takich jak pliki konfiguracyjne, dane użytkowników czy systemowe narzędzia, które mogłyby zostać wykorzystane w razie kompromitacji aplikacji. Mechanizm ten jest często stosowany w celu zwiększenia bezpieczeństwa, szczególnie w przypadku usług sieciowych, które mogą być potencjalnym wektorem ataku.

W kontekście lokalnego resolvera DNS, chrootowanie pozwala zminimalizować ryzyko związane z potencjalnymi podatnościami w jego kodzie. Resolver DNS, taki jak BIND lub Unbound, działa na styku wewnętrznej sieci i Internetu, co czyni go atrakcyjnym celem dla atakujących. Gdyby jednak został uruchomiony w środowisku chroot, atakujący, który uzyska dostęp do usługi, nie będzie w stanie wyjść poza ograniczoną przestrzeń systemu plików. W takiej przestrzeni znajdują się jedynie pliki niezbędne do działania resolvera, co uniemożliwia dostęp do krytycznych plików systemowych, takich jak hasła czy klucze prywatne. Dzięki temu chroot staje się skutecznym narzędziem redukcji potencjalnych szkód w przypadku kompromitacji aplikacji.

Tyle w teorii, chroot nie jest bowiem rozwiązaniem doskonałym. Nie zabezpiecza przed wszystkimi możliwymi atakami i powinien działać z innymi mechanizmami bezpieczeństwa, ale jest to na pewno dobry punkt wyjścia.

W tym artykule pokażę jak przygotować i uruchomić takie środowisko na przykładzie systemu CentOS Stream 9 oraz na prostym przykładzie pokażę, że jest szybciej niż odpytywanie zdalnego DNS’a.

Aktualizujemy system i instalujemy serwis:

dnf -y update

dnf install -y unbound

Tworzymy strukturę katalogów i plików:

mkdir -p /var/chroot/unbound

mkdir -p /var/chroot/unbound/var/lib

mkdir -p /var/chroot/unbound/etc

mkdir -p /var/chroot/unbound/var/log

mkdir -p /var/chroot/unbound/var/run

touch /var/chroot/unbound/var/log/unbound.log

chown -R unbound:unbound /var/chroot/unbound/var/log/unbound.log

Edytujemy konfigurację:

nano /etc/unbound/unbound.conf

Szukamy i zmieniamy poszczególne parametry:

server:

    chroot: „/var/chroot/unbound „

    directory: „/var/lib/unbound”

    logfile: „/var/log/unbound.log”

    username: „unbound”

cp -R /etc/unbound /var/chroot/etc/

Ustawiamy uprawnienia:

chown -R unbound:unbound /var/chroot/unbound/var/lib/unbound/

Jeśli wszystko ustawiliśmy poprawnie to sprawdzenie konfiguracji powinno zwrócić „no errors”.

unbound-checkconf

Uaktywniamy serwis w systemie i restartujemy:

systemctl enable –now unbound

systemctl restart unbound

Testujemy konfigurację:

dnf -y install dnsutils

dig MariuszQ.0.0.1 wp.pl

Porównanie czasów między lokalnym resolverem a zewnętrznym DNS:

dig @8.8.8.8 wp.pl

dig @9.9.9.9 wp.pl

Tymczasem na lokalnym serwerze:

dig MariuszQ.0.0.1 wp.pl

Przy jednym zapytaniu być może nie ma to dużego znaczenia, ale jeśli utrzymujemy tu środowisko, które odpowiada za hostowanie aplikacji do której uderza ruch wielkości kilkudziesięciu tysięcy zapytań to mogą zrobić się naprawdę duże różnice, idąc w sekundach. Lokalny resolver DNS, np. nasz przykładowy unbound, znacząco poprawia szybkość ładowania stron internetowych dzięki redukcji opóźnień związanych z zapytaniami DNS do zewnętrznych serwerów. Unbound przechowując wyniki zapytań w lokalnej pamięci podręcznej (w RAMie), kolejne żądania dotyczące tych samych domen są obsługiwane natychmiast, co eliminuje czas potrzebny na komunikację sieciową. W porównaniu z zdalnymi resolverami, lokalny Unbound działa bardziej efektywnie i mniej obciąża sieć i zasoby.

Uruchomienie dodatkowo Unbound’a w środowisku chroot dodaje istotną dodatkową warstwę bezpieczeństwa, izolując resolver od reszty systemu operacyjnego. W przypadku potencjalnej podatności lub kompromitacji usługi, atakujący jest ograniczony do ściśle określonej przestrzeni plików, co zapobiega eskalacji ataków i dostępowi do kluczowych zasobów systemowych.