Konfiguracja własnego routera — pfSense i iptables

18 października, 2023

Szybka konfiguracja:

Osoby zajmujące się zawodowo administracją IT, sieciami komputerowymi czy bezpieczeństwem, bardzo często do nauki i testowania różnych rozwiązań tworzą prywatne środowiska we własnej sieci. Do tych celów wykorzystuje się zwykle maszyny wirtualne, ale też dedykowane urządzenia, ponieważ nie każde oprogramowanie posiada możliwość „zwirtualizowania”. Poza tym w wielu przypadkach kluczowe jest pewne obycie z fizycznym sprzętem.

O ile dostępne na rynku hypervisor’y zapewniają różne opcje konfiguracji sieci, to jednak nie zawsze będą wystarczające dla naszych potrzeb. Zresztą, umiejętności związane z konfiguracją systemów do pracy, jako proste routery, należą do wiedzy podstawowej, której zwyczajnie się oczekuje, nawet jeśli nie zostały wyraźnie uwzględnione w ofertach pracy, np. dostępnych na portalu theprotocol.it. Trudno wyobrazić sobie, że ktoś pracuje na stanowisku w szeroko pojętej branży IT, ale przerasta go zadanie skonfigurowania typowego domowego routera.

W tym tekście przedstawię konfigurację maszyny z zainstalowanym wcześniej oprogramowaniem pfSense oraz alternatywny sposób z użyciem iptables w systemie Debian. pfSense to właściwie dystrybucja systemu FreeBSD pełniąca rolę routera i zapory sieciowej. Praktycznie wszystkie ustawienia możemy zmieniać z poziomu panelu w przeglądarce. Z kolei iptables jest powszechnie stosowanym w systemach Linux pakietem służącym do kompleksowego zarządzania ruchem sieciowym.

Maszyny wirtualne służące jako router powinny posiadać dwa interfejsy sieciowe — pierwsza karta jako NAT lub bridged i druga jako sieć wewnętrzna. W pokazanych przykładach stosuję sieć mostkowaną (maszyna wirtualna w sieci jest wtedy widziana jako osobny host i będzie osiągalna z jej poziomu), ponieważ omówiony zostanie m.in. port forwarding.

pfSense

Po pierwszym uruchomieniu maszyny z zainstalowanym pfSense zobaczymy ekran podobny do przedstawionego poniżej.

Ekran powitalny rozwiązania pfSense.
Ekran powitalny rozwiązania pfSense.

Podstawowym krokiem będzie ustawienie adresacji. Wszystkie moje maszyny wirtualne mają przypisane adresy z sieci 10.0.0.0/24, więc potrzebuję zmienić domyślny w pfSense adres 192.168.1.1. Nie zamierzam ponadto używać serwera DHCP, każda maszyna ma własny adres statyczny. Wybieramy więc opcję 2, a następnie lokalny interfejs (LAN) i podajemy szczegóły dotyczące tworzonej sieci. Jako adres routera zwykle (nie ma tutaj żadnych zasad) ustawia się pierwszy możliwy z dostępnej puli, czyli 10.0.0.1. Poszczególne kluczowe „pytania” są następujące:

  • numer interfejsu do skonfigurowania: 2, czyli sieć LAN, po stronie WAN adresy będą otrzymywane z serwera DHCP
  • adres IPv4 interfejsu LAN z serwera DHCP: wybieramy n
  • adres routera po stronie LAN: wpisujemy 10.0.0.1
  • maska sieci LAN: wpisujemy 24
  • adres IPv4 interfejsu IPv6 z serwera DHCP: wybieramy n
  • uruchomienie serwera DHCP po stronie LAN: wybieramy n
  • dostępność panelu protokołem HTTP: wybieramy y
 

Pozostałą konfigurację należy przeprowadzić poprzez panel w przeglądarce. Wchodzimy w tym celu na adres http://10.0.0.1. Domyślne dane logowania to użytkownik admin i hasło pfsense. Przy pierwszym logowaniu pojawi się wizard pfSense Setup.

Konfiguracja początkowa pfSense.

Pozostawiamy raczej domyślne opcje, natomiast ważne jest, aby w kroku nr 3 ustawić strefę czasową na Europe/Warsaw, a w kroku nr 6 podać nowe hasło dla użytkownika admin.

Przypiszemy teraz trzy wirtualne adresy IP, które będą używane jako adresy wyjściowe dla dwóch hostów (ruch wychodzący z tych hostów nie będzie widoczny jako adres WAN routera, a jako dedykowany adres IP) oraz jako adresy, pod którymi dostępne będą usługi udostępniane przez te serwery (HTTP/HTTPS dla dwóch maszyn oraz OpenVPN).

Przechodzimy do zakładki Firewall -> Virtual IPs i wybieramy Add. Jako Type zaznaczamy IP Alias oraz podajemy wybrany adres IP wraz z maską. Tę prostą operację wykonujemy dla każdego z trzech adresów.

Dodawanie IP alias w pfSense.

Dodatkowe adresy zostały przypisane do pfSense.

Lista wirtualnych adresów IP w pfSense.

Konfiguracja przekierowania portów również nie jest wyjątkowo skomplikowana, ponieważ wystarczy w karcie Port Forward w zakładce Firewall -> NAT dodać odpowiednie reguły. Widocznych będzie kilka opcji, natomiast interesuje nas właściwie tylko sześć z nich:

  • Destination: adres zewnętrzny, pod którym docelowa usługa ma być dostępna
  • Destination port range: protokół / port zewnętrzny, który ma kierować na daną usługę w sieci LAN
  • Redirect target IP: adres lokalny hosta wystawiającego określoną usługę (Type jako Single host)
  • Redirect target port: protokół / port lokalny, pod którym usługa działa
  • Filter rule association: tutaj Pass, ponieważ chcemy zezwolić na ten ruch
 

Poniższy zrzut ekranu przedstawia przykład port forwarding dla protokołu HTTPS z adresu 192.168.1.150 na adres 10.0.0.50.

Konfiguracja port forwarding w pfSense.

Od teraz powinniśmy posiadać możliwość dostępu z naszej sieci do usług działających w obrębie sieci wewnętrznej maszyn wirtualnych.

Dostęp do usługi w sieci wewnętrznej z poziomu sieci WAN.

Niezależnie od tych ustawień ruch wychodzący z hostów dodanych w regułach port forwarding wciąż jest widoczny pod adresem WAN pfSense, a nie jako przypisane dodatkowe adresy IP. Przykład dla hosta 10.0.0.30, który ma ustawione przekierowanie ruchu HTTP/HTTPS z adresu 192.168.1.130:

Sprawdzenie wyjściowego adresu IP.

Pod adresem 192.168.1.105 działa serwer WWW hostujący prosty skrypt PHP zwracający adres IP klienta. Jak widać, został zwrócony adres IP routera. Nie jest to sytuacja właściwa, ale rozwiązaniem będzie konfiguracja NAT 1:1. Będąc w zakładce Firewall -> NAT przechodzimy do karty 1:1, gdzie dodajemy odpowiednie reguły. Tutaj dla nas znaczące są wyłącznie dwie opcje — External subnet IP i Internal IP. Ich znaczenia można się domyślić.

Konfiguracja NAT 1:1 w pfSense.

Opisany problem został w ten sposób naprawiony.

Sprawdzenie wyjściowego adresu IP.

Pozostaje jeszcze jedna dość istotna kwestia, czyli ewentualna próba wejścia na dodatkowy adres z jednej z maszyn wirtualnych. Poprzednio sprawdziliśmy, że odwiedzenie adresu http://192.168.1.130 z sieci domowej działa poprawnie i zwraca odpowiedź serwera WWW. Tymczasem z poziomu sieci wewnętrznej maszyn wirtualnych…

Działanie NAT z poziomu sieci lokalnej.

…widzimy panel logowania do pfSense. Nie jest to żaden błąd, a standardowe działanie NAT. Aby umożliwić uznaną przez nas za właściwą obsługę takowych żądań, wystarczy w zakładce System -> Advanced i karcie Firewall & NAT ustawić NAT Reflection mode for port forwards na Pure NAT oraz aktywować opcje Enable NAT Reflection for 1:1 NAT i Enable automatic outbound NAT for Reflection.

Bardzo możliwe, że osoby bez większego doświadczenia (szczególnie praktycznego zdobytego w dobrej pracy) nie zwróciłyby uwagi na te dwa „problemy”. Świadomość podobnych zagadnień z pewnością jest wartością dodaną. Natomiast oprócz zdobywania doświadczenia komercyjnego warto poświęcać czas na przyswajanie wiedzy z różnych źródeł, np. tematycznych blogów takich jak blog.theprotocol.it.

Konfigurację sieciową zakończymy wyłączeniem usługi DNS Resolver i włączeniem DNS Forwarder (pfSense używa w tym celu dnsmasq). Oba znajdziemy w zakładce Services. Umożliwi to połączenie z Internetem.

Proponuję jeszcze zintegrować pfSense z Active Directory, aby wybrani użytkownicy mogli wykonywać operacje w panelu. W pierwszej kolejności tworzymy w dsa.msc grupę, do której przypisujemy użytkowników mających docelowo posiadać uprawnienia administratora w pfSense. Potrzebujemy też dedykowanego użytkownika, ponieważ poprzez jego poświadczenia będziemy mogli połączyć pfSense z Active Directory. W moim przypadku grupę ambitnie nazwałem Siec, a użytkownika — router.

W pfSense przechodzimy do zakładki System -> User Manager i dalej do karty Authentication Servers. Dodajemy kolejny wpis, w którym interesują nas w zasadzie poniższe parametry:

  • Descriptive name: zwykła nazwa dla odróżnienia nowego wpisu od pozostałych
  • Hostname or IP address: nazwa domenowego lub adres IP kontrolera domeny
  • Search scope
    • Level: Entire Subtree
    • Base DN: standardowy zapis, przykład dla domeny avlab.local to dc=avlab,dc=local
  • Authentication containers: wszystkich użytkowników przechowywuję w osobnej jednostce organizacyjnej Firma, więc podaję ou=Firma,dc=avlab,dc=local
  • Bind anonymous: należy odznaczyć opcję Use anonymous binds to resolve distinguisged names
  • Bind credentials: tutaj poświadczenia dla dodanego dedykowanego użytkownika, w moim przypadku: cn=router,ou=Firma,dc=avlab,dc=local i jego hasło
  • Initial Template: wybieramy z listy Microsoft AD
  • Group Object Class: wpisujemy sugerowaną wartość, czyli posixGroup

 

Pozostałe opcje mogą pozostać domyślne. Działanie logowania domenowego warto przetestować wchodząc w Diagnostics -> Authentication i uzupełniając formularz.

Udane testowe logowanie z użyciem AD.

Teraz powinniśmy dodać grupę odpowiadającą nazwie grupy z Active Directory. Można to wykonać w zakładce System -> User Manager i w karcie Groups.

Dodawanie grupy w pfSense.

Zapisujemy zmiany i wracamy do edycji dodanej grupy, ponieważ przy dodawaniu nie ma możliwości ustawienia uprawnień członków. Zależy nam, aby użytkownicy z grupy Siec mogli wykonywać wszystkie operacje, więc w sekcji Assigned Privileges wybieramy WebCfg – All pages. Na koniec przechodzimy jeszcze do karty Settings i jako Authentication Server wybieramy utworzony wcześniej.

Logowanie domenowe powinno być już możliwe. Na poniższym zrzucie ekranu widać, że udało się zalogować użytkownikowi z domeny.

Logowanie z użyciem AD.

Natomiast w sytuacji, gdy zaloguje się użytkownik spoza grupy Siec, zobaczy komunikat informujący, że nie ma przypisanych żadnych stron. Nie może więc wykonywać żadnej operacji w pfSense.

Brak dostępu dla użytkownika spoza grupy.

iptables

Nie potrzebujemy korzystać z oprogramowania pokroju pfSense, ponieważ wszelkie opisane powyżej funkcje możemy z powodzeniem uzyskać z użyciem iptables i właściwie dowolnej dystrybucji systemu Linux. W tym tekście używam akurat systemu Debian. Podłączone są dwie wirtualne karty sieciowe. Ta po stronie WAN otrzymuje adres z serwera DHCP, natomiast działająca w obrębie sieci lokalnej ma przypisany statyczny adres IP 10.0.0.1.

Na początku instalujemy pakiety, które będziemy wykorzystywać:

				
					apt install iptables-persistent dnsmasq freeipa-client sudo
				
			

iptables-persistent pozwala zachować dodane reguły iptables. Wykonanie polecenia iptables z odpowiednią regułą sprawi, że ta reguła zostanie natychmiast załadowana, natomiast wystarczy restart systemu, aby przestała obowiązywać. Nie jest to może złe rozwiązanie, ponieważ jeśli popełnimy błąd i przykładowo zablokujemy dostęp do wybranej usługi, to po restarcie wszystko powróci do poprawnego stanu. Wyjątkiem jest oczywiście SSH, dlatego należy zachować ostrożność, jeśli do systemu nie mamy innego dostępu (np. poprzez konsolę KVM). Z drugiej strony zawsze proponuję blokować dostęp do usług na wyższym poziomie, czy to w ustawieniach instancji u wybranego dostawcy chmury, czy też na poziomie oprogramowania do wirtualizacji.

dnsmasq to zwyczajny forwarder DNS, który pozwala przekazywać zapytania do serwera DNS z sieci lokalnej. Z kolei freeipa-client umożliwi dodanie hosta do serwera FreeIPA, który stanowi świetną alternatywę dla Active Directory w środowiskach Linux. Pakiet sudo jest wymagany przez FreeIPA, aby administratorzy (użytkownicy przypisani do odpowiedniej Sudo Rules) mogli wykonywać polecenia jako root.

Szersze omówienie FreeIPA zdecydowanie wykracza poza ramy tego tekstu, ale zachęcam do samodzielnego zapoznania się z tym rozwiązaniem. Znajomość podobnych narzędzi jest standardowym wymaganiem w ofertach pracy dla specjalistów zajmujących się security.

W pfSense dodawaliśmy wirtualne adresy IP. Tutaj też istnieje taka możliwość, trzeba jednak te adresy zwyczajnie dopisać do interfejsu zewnętrznego. W systemie Debian konfiguracja adresacji znajduje się w pliku /etc/network/interfaces. Wystarczy dopisać:

				
					iface enp0s3:0 inet static
address 192.168.1.130
netmask 255.255.255.0

iface enp0s3:1 inet static
address 192.168.1.150
netmask 255.255.255.0

iface enp0s3:2 inet static
address 192.168.1.15
netmask 255.255.255.0
				
			

Należy pamiętać, aby dodane interfejsy automatycznie „wstawały” po restarcie systemu. Ich nazwy muszą znaleźć się w opcji auto i allow-hotplug.

FreeIPA wymaga, aby nazwy hostów zawierały domenę, dlatego edytujemy pliki /etc/hostname i /etc/hosts, po czym restartujemy system. Aby dołączyć host do domeny, wystarczy wykonać polecenie ipa-client-install –mkhomedir (ten parametr odpowiada za automatyczne tworzenie katalogów domowych przy pierwszym logowaniu użytkownika). Pojawi się kilka opcji do wypełnienia:

  • Provide the domain name of your IPA server (ex: example.com)
  • Provide your IPA server name (ex: ipa.example.com)
  • Proceed with fixed values and no DNS discovery? [no]
  • Do you want to configure chrony with NTP server or pool address? [no]
  • Continue to configure the system with these values? [no]
  • User authorized to enroll computers
  • Password for [email protected]

 

W naszym przypadku zostały podane następujące parametry:

  • avlab.local
  • ipa.avlab.local
  • yes
  • no
  • yes
  • nazwa użytkownika administratora w FreeIPA
  • hasło powyższego użytkownika

 

Poprawne zakończenie procesu dodawania hosta do serwera FreeIPA zakończy się komunikatami podobnymi do tych ze zrzutu ekranu.

Dodawanie hosta do FreeIPA.

Host będzie ponadto widoczny w panelu usługi FreeIPA.

Hosty dodane do FreeIPA.

Dostępne będzie już także logowanie użytkownikami z bazy FreeIPA. Możemy przystąpić do właściwej konfiguracji.

Przede wszystkim należy zezwolić na przekazywanie pakietów. Aby zmiana była trwała, należy ją zapisać w pliku /etc/sysctl.conf i przeładować parametry kernela poleceniem sysctl:

				
					sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sudo sysctl -p
				
			

Pierwsza dodana przez nas reguła iptables pozwoli na obsługę pakietów wysyłanych przez pozostałe hosty w sieci. Bez jej ustawienia żadne pakiety nie zostaną przekazane na zewnątrz. To podstawowa reguła działania każdego routera.

				
					sudo iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
				
			

Należy zadbać o odpowiednie zabezpieczenia. Aktualnie do naszego routera dostęp SSH jest możliwy „z zewnątrz”, nie tylko z sieci wewnętrznej. W celu ograniczenia tego dostępu wyłącznie do adresu lokalnego wystarczy wykonać:

				
					sudo iptables -A INPUT -d 10.0.0.1 -p tcp --dport 22 -j ACCEPT
sudo iptables -P INPUT DROP
				
			

Zablokowaliśmy całkowicie ruch wchodzący z wyjątkiem połączeń na port 22 (SSH) adresu 10.0.0.1. Tutaj kolejność ma znaczenie — najpierw zezwoliłem na ruch SSH, aby uniknąć sytuacji „odcięcia” dostępu do serwera. Trzeba jednak dodać jeszcze inne reguły zabezpieczające:

				
					sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
				
			

Bez nich zarówno router, jak i inne hosty w sieci nie będą miały dostępu na zewnątrz. Zezwoliliśmy więc na forward pakietów i ruch wychodzący. Ponadto odblokowaliśmy ruch przychodzący na interfejs lo oraz te pakiety będące w stanie ESTABLISHED,RELATED. Zezwoliliśmy też na połączenia UDP na porcie 53 (DNS). Dopiero to wszystko razem umożliwi komunikację na zewnątrz.

Można powiedzieć, że sieć w podstawowym zakresie działa poprawnie. Jest to więc dobry moment na zapisanie dodanych reguł, które, przypomnę, bytują obecnie tylko w pamięci operacyjnej, nie są dodane na stałe. Polecenie iptables-save służy do ich wyświetlenia.

Wypisanie aktualnych reguł zapory poleceniem iptables-save.
Wypisanie aktualnych reguł zapory poleceniem iptables-save.

Widać wszystkie uprzednio dodane reguły. Właśnie ten wynik polecenia iptables-save jest we właściwym formacie rozpoznawanym przez usługę netfilter-persistent, która odpowiada ze załadowanie reguł przy starcie systemu. Reguły odczytywane są z plików /etc/iptables/rules.v4 (dla IPv4) i /etc/iptables/rules.v6 (dla IPv6). Do tego pierwszego pliku zapiszemy nasze reguły.

Zwykle w celu przekierowania wyniku polecenia do pliku używany jest znak strumienia >. Jednak w lokalizacji /etc/iptables może zapisywać użytkownik root. Wykonanie polecenia iptables-save poprzedzone sudo nie umożliwi zapisu pliku. Mniej profesjonalnym rozwiązaniem jest chwilowe zalogowanie się na użytkownika root i wykonanie

				
					iptables-save > /etc/iptables/rules.v4
				
			

Jednak lepszy pomysł zakłada wykorzystanie potoku (pipe) i polecenia tee, które zapisze wynik z polecenia podanego przed znakiem |. Domyślne zachowanie tee to nadpisywanie, w celu dopisania zawartości należy użyć przełącznika -a.

				
					sudo iptables-save|sudo tee /etc/iptables/rules.v4
				
			

W panelu pfSense dodawaliśmy przekierowania portów dla konkretnych adresów IP. W iptables takowe operacje ograniczają się do jednego polecenia:

				
					sudo iptables -t nat -A PREROUTING -p tcp -d 192.168.1.150 --dport 443 -j DNAT --to-destination 10.0.0.50:443
				
			

W powyższym przykładzie ruch TCP na porcie 443 z adresu 192.168.1.150 przekierowujemy na adres 10.0.0.50 i port 443. Adres 192.168.1.150 został zapisany wcześniej w pliku /etc/network/interfaces.

iptables pozwala także na dodawanie reguł NAT 1:1, aby konkretne hosty na zewnątrz były widoczne pod swoimi dedykowanymi adresami, a nie adresami routera. Przykładowa reguła jest bardzo prosta:

				
					sudo iptables -t nat -A POSTROUTING -s 10.0.0.50 -j SNAT --to-source 192.168.1.150
				
			

Podobnie jak w przypadku pfSense próba połączenia się z poziomu sieci wewnętrznej na jeden z dodatkowych adresów IP spowoduje połączenie z serwerem z systemem Debian. Tutaj rozwiązaniem jest zwykłe ustawienie MASQUERADE, ale dla interfejsu po stronie LAN.

				
					sudo iptables -t nat -A POSTROUTING -o enp0s8 -j MASQUERADE
				
			
Picture of Michał Giza

Michał Giza

Autor tekstów na portalu Fundacji AVLab dla Cyberbezpieczeństwa. Administrator systemów Linux i Windows Server.
Picture of Michał Giza

Michał Giza

Autor tekstów na portalu Fundacji AVLab dla Cyberbezpieczeństwa. Administrator systemów Linux i Windows Server.

PODZIEL SIĘ:

guest
0 komentarzy
Inline Feedbacks
View all comments

Wyrażam zgodę na przesłanie oferty drogą telefoniczną przez IT Partners security sp. z o.o. z siedzibą Katowicach ul.Padereskiego 35 na podany przeze mnie adres e-mail zgodnie z ustawą z dnia 10 maja 2018 roku o ochronie danych osobowych (Dz. Ustaw z 2018, poz. 1000) oraz zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych oraz uchylenia dyrektywy 95/46/WE (RODO).

Wyrażam zgodę na przesłanie oferty drogą mailową przez IT Partners security sp. z o.o. z siedzibą Katowicach ul.Padereskiego 35 na podany przeze mnie adres e-mail zgodnie z ustawą z dnia 10 maja 2018 roku o ochronie danych osobowych (Dz. Ustaw z 2018, poz. 1000) oraz zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych oraz uchylenia dyrektywy 95/46/WE (RODO).

[ninja_tables id=”27481″]