Konfiguracja własnego routera — pfSense i iptables

avlab.pl 1 rok temu
Zdjęcie: pfsense


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 najważniejsze 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, choćby jeżeli nie zostały wyraźnie uwzględnione w ofertach pracy, np. dostępnych na portalu theprotocol.it. Trudno wyobrazić sobie, iż 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 adekwatnie 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.

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 najważniejsze „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.

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 wszystkich z trzech adresów.

Dodatkowe adresy zostały przypisane do 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 adekwatnie 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.

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.

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:

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 adekwatna, 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ć.

Opisany problem został w ten sposób naprawiony.

Pozostaje jeszcze jedna dość istotna kwestia, czyli ewentualna próba wejścia na dodatkowy adres z jednej z maszyn wirtualnych. Poprzednio sprawdziliśmy, iż 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…

…widzimy panel logowania do pfSense. Nie jest to żaden błąd, a standardowe działanie NAT. Aby umożliwić uznaną przez nas za adekwatną 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, iż 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.

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.

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ć, iż udało się zalogować użytkownikowi z domeny.

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

iptables

Nie potrzebujemy korzystać z systemu pokroju pfSense, ponieważ wszelkie opisane powyżej funkcje możemy z powodzeniem uzyskać z użyciem iptables i adekwatnie 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, iż 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żeli 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żeli 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 systemu 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 admin@AVLAB.LOCAL

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.

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

Dostępne będzie już także logowanie użytkownikami z bazy FreeIPA. Możemy przystąpić do adekwatnej 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ć, iż sieć w podstawowym zakresie działa poprawnie. Jest to więc dobry moment na zapisanie dodanych reguł, które, przypomnę, bytują w tej chwili 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.

Widać wszystkie uprzednio dodane reguły. Właśnie ten wynik polecenia iptables-save jest we adekwatnym 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
Idź do oryginalnego materiału