Konfiguracja zapory sieciowej jest istotnym krokiem do podwyższenia bezpieczeństwa jakiegokolwiek systemu operacyjnego. Większość dystrybucji Linuxa posiada kilka różnych narzędzi do zapór sieciowych, które możemy użyć do skonfigurowania naszej. W tym przewodniku opowiemy o zaporze Iptables.
Iptables jest standardową zaporą sieciową zwarta w większości dystrybucji Linuxa domyślnie (nowoczesny wariant nftables zacznie ją zastępować). Jest to właściwie początkowe stadium procesu haków netfilter na poziomie kernel, które mogą manipulować stos sieciowy Linuxa. Działa ona dzięki dopasowywaniu każdego pakietu, który przechodzi przez interfejs sieciowy do zestawu reguł, które decydują, co zrobić.
W tym przewodniku pójdziemy o krok dalej, do praktycznego przykładu, aby zademonstrować to, jak stworzyć podstawowy zestaw reguł dla serwera Ubuntu 16.04. W rezultacie, zapora sieciowa umożliwi ruch SSH i HTTP.
Uwaga: Ten tutorial obejmuje ochronę IPv4. W Linuksie ochrona IPv6 jest utrzymywana oddzielnie od IPv4. Na przykład, „Iptables” utrzymuje jedynie reguły zapory sieciowej dla adresów IPv4, ale ma również odpowiednik IPv6, zwany „Ip6ables”, który może być używany do utrzymywania reguł dla adresów sieciowych IPv6.
Jeśli Twój VPS jest skonfigurowany pod IPv6, proszę, pamiętaj o zabezpieczeniu interfejsów zarówno dla IPv4 i IPv6 przy użyciu odpowiednich narzędzi.
Wymagania
Zanim zaczniesz korzystać z tego tutorialu, powinieneś mieć osobne konto, nie root – z przywilejami sudo – utworzone na swoim serwerze. Jeśli potrzebujesz pomocy z utworzeniem go, podążaj za tym przewodnikiem: Wstępna Konfiguracja Serwera z Ubuntu 16.04.
Podstawowe komendy Iptables
Teraz, kiedy już dobrze rozumiesz koncepcję Iptables, powinniśmy powiedzieć o podstawowych komendach, jakie będą używane do określenia złożonych zestawów reguł do ogólnego zarządzania interfejsem Iptables.
Na początek, musisz być świadomy tego, że komendy Iptables muszą być uruchamiane z przywilejami root. Oznacza to, że musisz zalogować się jako root, użyć su
lub sudo -i
, aby wejść do konsoli pod root`em, lub poprzedzić wszystkie komendy używając sudo
. Użyjemy w tym przewodniku sudo
, jako preferowana metoda w systemie Ubuntu.
Dobrym punktem startowym jest stworzenie listy reguł, które są konfigurowane dla Iptables. Możesz zrobić to za pomocą flagi –L
:
sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Jak widzisz, mamy nasze trzy domyślne bramy (INPUT, OUTPUT i FORWARD). Możemy również zobaczyć domyślną politykę każdej z bramy (każdy ma ACCEPT jako domyślną opcję). Widzimy też nagłówki kolumn, ale nie widzimy żadnych reguł. Jest tak dlatego, że Ubuntu nie działa z domyślnym zestawem reguł.
Możemy zobaczyć odpowiedź w formacie, który odzwierciedla komendy potrzebne do włączenia każdej z reguł i polityki poprzez użycie flagi –S
.
sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
Żeby replikować konfigurację, musimy po prostu wpisać sudo iptables
, po którym ma następować każda z linijek odpowiedzi (w zależności od konfiguracji, może to być właściwie nieco bardziej skomplikowane, jeśli jesteśmy połączeni zdalnie, musimy uważać na to, aby nie wyłączyć nasze aktualne połączenie).
Jeśli Twoje reguły są na miejscu i chcesz się ich pozbyć, i zacząć od początku, możesz to zrobić poprzez wpisanie:
sudo iptables -F
Jeszcze raz, domyślna polityka jest tutaj ważna, dlatego że podczas gdy wszystkie reguły zostaną usunięte z Twoich bram, polityka domyślna nie zmieni się z tą komendą. Oznacza to, iż jeśli jesteś połączony zdalnie, musisz upewnić się, że domyślna polityka na Twoich ramach INPUT i OUTPUT jest ustawiona na ACCEPT przed pozbyciem się reguł. Możesz to zrobić poprzez wpisanie:
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -F
Możesz zatem zmienić domyślną drop politykę z powrotem na DROP po tym, jak ustanowiłeś reguły, które wyraźnie pozwolą na Twoje połączenie. Przejdziemy do tego już za chwilę.
Tworzenie pierwszej reguły
Zaczniemy od konfiguracji polityk bezpieczeństwa naszej zapory sieciowej. Jak zostało powiedziane powyżej, będziemy pracować z bramą INPUT, jako że jest to rozdzielacz, którym przychodzący ruch sieciowy będzie przesyłany. Zaczniemy od reguły, o której wspominaliśmy wcześniej: reguła, która wyraźnie akceptuje Twoje obecne połączenie SSH.
Cała reguła, jakiej potrzebujemy, wygląda tak:
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Może wydawać się to niesamowicie skomplikowane, ale większość z tego będzie miała sens, jak tylko spojrzymy bliżej na komponenty:
- –A INPUT: Flaga
–A
dodaje regułę do końcówki łańcucha. Jest to częścią komendy, która przekazuje Iptables, że chcemy dodać nową regułę, i że chcemy dodać ją do końca łańcucha oraz że łańcuch, na którym chcemy operować, to łańcuch INPUT - –m conntrack: Iptables ma nie tylko wiele bazowych funkcji, ale również dużo dodatków i modułów, które zapewniają dodatkowe możliwości
W tej części polecenia oświadczyliśmy, że chcemy mieć dostęp do funkcji zapewnianej przez moduł conntrack
. Ten moduł pozwala na dostęp do komend, które mogą być użyte do podjęcia decyzji opartych na relacji pakietu danych z poprzednimi połączeniami.
- –ctstate: To jest jedna z komend, którą można uruchomić przy użyciu modułu conntrack. Ta komenda pozwala nam na dopasowanie pakietów na podstawie tego, jak są one związane z pakietami, które widzieliśmy wcześniej.
Przekazujemy wartość ESTABLISHED
, aby dać zezwolenie pakietom będącym częścią istniejącego połączenia. Przekazujemy jej wartość RELATED
, aby dać zezwolenie pakietom będącym powiązanymi z nawiązanym połączeniem. To jest porcja reguły, która pasuje do naszej obecnej sesji SSH.
- -j ACCEPT: To precyzuje obiekt docelowy pasujących pakietów. Tutaj mówimy Iptables, że pakiety, które pasują do poprzedzających kryteriów, powinny zostać zaakceptowane i przepchnięte dalej.
Umiejscawiamy tą regułę na początku, gdyż chcemy upewnić się, że połączenia, których już używamy, są zaakceptowane i wyciągnięte z łańcuchem przed dotarciem to jakichś reguł DROP.
Możemy zobaczyć zmiany po wyświetleniu reguł:
sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Teraz, kiedy znasz już ogólną składnię, możemy kontynuować poprzez dodanie kilku przypadków, gdzie będziemy chcieli zaakceptować połączenie.
Akceptacja innych niezbędnych połączeń
Przekazaliśmy Iptables, aby utrzymał otwarte wszystkie te połączenie, które już są otwarte oraz, aby dał zezwolenie na inne połączenia związane z tymi. Jednakże, musimy stworzyć jakieś reguły, aby ustalić, kiedy chcemy zaakceptować nowe połączenie, które nie spełniają podanych wyżej kryteriów.
Chcemy utrzymać otwarte szczególnie dwa porty. Chcemy mieć otwarty port SSH (w tym przewodniku zakładamy, że jest to domyślny 22. Jeśli zmieniłeś to w konfiguracji SSH, zmodyfikuj tu wartość). Założymy również, że na tym komputerze serwer sieciowy działa na domyślnym porcie 80. Jeśli sprawa nie wygląda tak w Twoim przypadku, nie musisz dodawać tej reguły.
Dwie linijki, jakich mamy zamiar użyć, wyglądają tak:
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
Jak widzisz, są one bardzo podobne do naszej pierwszej reguły, chociaż może nieco prostsze. Nowymi opcjami są:
- -p tcp: Ta opcja sprawdza protokół przesyłanych pakietów, czy lecą oni przez TCP. Jest to protokół oparty na połączeniu, który będzie używany przez większość aplikacji, gdyż zezwala na komunikację godną zaufania.
- -dport: Ta opcja jest dostępna, jeśli podana jest flaga
–p tcp
. Powoduje to dalszy wymóg otwartych portów do pakietów. Pierwsza reguła pasuje do pakietów TCP przeznaczonych dla portu 22, podczas gdy druga reguła pasuje do ruchu TCP skierowanego w stronę portu 80.
Istnieje jeszcze jedna reguła, przy której musimy się upewnić, że nasz serwer może funkcjonować poprawnie. Często bywa tak, że usługi komputerowe komunikują się ze sobą poprzez przesyłanie sobie nawzajem pakietów sieciowych. Robią to poprzez utylizację pseudo sieciowego interfejsu, nazywane loopback device, które przekierowuje ruch z powrotem do niego, zamiast do innych komputerów.
Więc jeśli ktoś chce skontaktować się z inną usługą, która słucha połączeń z portu 4555, może wysłać pakiet do portu 4555 w urządzeniu sprzężenia zwrotnego. Chcemy zezwolić tego rodzaju działania, ponieważ jest to konieczne dla prawidłowego działania wielu programów.
Reguła, jaką musimy dodać, wygląda tak:
sudo iptables -I INPUT 1 -i lo -j ACCEPT
Wygląda to nieco inaczej niż nasze pozostałe komendy. Przeanalizujmy to, co to robi:
- -I INPUT 1: Flaga
–I
mówi Iptables, aby dodał nową regułę. Jest inaczej niż w przypadku flagi–A
, który dodaje regułę na koniec. Flaga–I
zabiera łańcuch i pozycję reguły tam, gdzie chcesz wprowadzić nową regułę.
W tym przypadku, dodajemy tą regułę jako pierwszą w łańcuchu INPUT. To ściągnie na dół pozostałe reguły. Tą chcemy mieć na samej górze, bo jest fundamentalna i kolejne reguły nie powinny mieć na nią wpływu.
- -i lo: Ten komponent reguły sprawdza, czy interfejs, którego używa pakiet, jest interfejsem “lo”. Interfejs „lo” to inna nazwa dla urządzenia sprzężenia zwrotnego. Oznacza to, że jakikolwiek pakiet używającego tego interfejsu do komunikacji (pakiety generowane na naszym serwerze dla Twojego serwera) powinien zostać przyjęty.
Aby zobaczyć nasze aktualne reguły, powinieneś użyć flagi –S
. Jest tak dlatego, że flaga –L
nie zawiera niektórych informacji, takich jak interfejs, do którego przywiązana jest flaga, co jest ważną częścią reguły, którą właśnie dodaliśmy:
sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
Wprowadzania Reguły Drop
Obecnie mamy cztery oddzielne reguły, które wyraźnie akceptują pakiety na podstawie określonych kryteriów. Jednakże, nasza zapora sieciowa w tym momencie nie blokuje niczego.
Jeśli pakiet wejdzie do łańcucha INPUT i nie będzie pasował do żadnej z czterech reguł, które stworzyliśmy, on jest przekazywany dalej do polityki domyślnej, która oznacza akceptację pakietu mimo wszystko. Musi to zostać zmienione.
Istnieją dwa różne sposoby na zrobienie tego, mające kilka ważnych różnic.
Pierwszym sposobem jest modyfikacja domyślnej polityki naszego łańcucha INPUT. Możemy to zrobić poprzez wpisanie:
sudo iptables -P INPUT DROP
To wyłapie każdy pakiet przechodzący przez łańcuch INPUT i zablokuje go.
Może to być bezpieczniejsze, ale również mieć poważne konsekwencje, jeśli nie masz innego sposobu na uzyskanie dostępu do swojego serwera. Z panelem od Hostovita możesz zalogować się przez naszą konsolę sieciową na stronie z aktywnym produktem, aby uzyskać dostęp do Twojego serwera, jeśli tak się stanie.
Ewentualnie będziesz chciał, aby Twój serwer automatycznie blokował wszystkie połączenia w przypadku, gdy reguły są odrzucane. To mogłoby uchronić Twój serwer przed byciem szeroko otwartym. Oznacza to również, że możesz z łatwością dodać reguły do końcówki łańcucha podczas zrzucania pakietów w taki sposób, jaki chcesz.
Alternatywnym podejściem jest utrzymanie domyślnej polityki dla łańcucha jako zaakceptowanej i dodanie reguły, która zrzuca każdy pozostawiony pakiet na dół łańcucha sama.
Jeśli zmieniłeś powyżej domyślną politykę dla łańcucha INPUT, możesz ustawić ją z powrotem poprzez wpisanie:
sudo iptables -P INPUT ACCEPT
Teraz możesz dodać regułę na dole łańcucha, która zablokuje wszystkie pozostające pakiety:
sudo iptables -A INPUT -j DROP
Rezultat, przy normalnie operujących warunkach, jest dokładnie taki sam jak przy domyślnej polityce blokad. Ta reguła działa dzięki dopasowywaniu każdego pozostającego pakietu, który jej dosięga. To powstrzymuje pakiet przez zrzucaniem, aby osiągnąć domyślną politykę.
Właściwie, używa się tego, aby utrzymać domyślną politykę przy akceptowaniu ruchu. Tym sposobem, jeśli są jakiekolwiek problemy i reguły są odrzucane, wciąż będziesz w stanie uzyskać dostęp do maszyny przez sieć. Jest to sposób na wprowadzenie w życie domyślnej akcji bez zmieniania polityki, która może być wprowadzona do pustego łańcucha.
Oczywiście, oznacza to również, że jakakolwiek dodatkowa reguła, jakąś chcesz dodać na koniec łańcucha, będzie musiała zostać dodana przed regułą z blokadą. Możesz zrobić to albo poprzez czasowe usunięcie reguły z blokadą:
sudo iptables -D INPUT -j DROP
sudo iptables -A INPUT nowa_regula
sudo iptables -A INPUT -j DROP
Albo, możesz wprowadzić reguły, jakich potrzebujesz na końcu łańcucha (przed blokadą) poprzez sprecyzowanie numeru linii. Aby wprowadzić regułę do linii numer 4, możesz wpisać:
sudo iptables -I INPUT 4 nowa_regula
Jeśli masz problem ze znalezeniem numeru linii, która odpowiada pewnej regule, możesz powiedzieć Iptables, aby ponumerował każdą z nich poprzez wpisanie:
sudo iptables -L --line-numbers
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
3 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
4 ACCEPT tcp -- anywhere anywhere tcp dpt:http
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
Może to być pomocne przy upewnianiu się, że dodajesz reguły w odpowiednim dla nich miejscu.
Zapisywanie konfiguracji Iptables
Domyślnie, reguły, które dodajesz do Iptables, są efemeryczne (krótkotrwałe). Oznacza to, że kiedy zrestartujesz swój serwer, oni znikną.
Jest to właściwie dobra cecha dla niektórych użytkowników, bo daje im to drogę powrotną, jeśli przypadkowo zablokowali sobie dostęp do serwera. Jednakże, większość użytkowników będzie chciało sposób na to, aby automatycznie zapisywać reguły, które stworzyli i załadowywać je, kiedy serwer znów zacznie działać.
Istnieje kilka sposobów na zrobienie tego, ale najłatwiejsza wiąże się z pakietem iptables-persistent
. Możesz ściągnąć ją z domyślnych repozytoriów Ubuntu:
sudo apt-get update
sudo apt-get install iptables-persistent
Podczas instalacji, zostaniesz poproszony o to, czy nie chcesz zapisać swoich obecnych reguł, aby były później automatycznie załadowane. Jeśli podoba Ci się Twoja obecna konfiguracja (i przetestowałeś swoją możliwość stworzenia niezależnego połączenia SSH), możesz wybrać opcję zapisania obecnych reguł.
Zostaniesz zapytany również o to, czy chcesz zapisać reguły IPv6, które skonfigurowałeś. One są konfigurowane przez osobne narzędzie, zwane ip6ables
, które kontroluje przepływ pakietów IPv6 w taki sam sposób.
Jak tylko instalacja zostanie zakończona, będziesz miał nowy serwis, zwany iptables-persintent
, który jest skonfigurowany tak, aby działać od zera. Ten serwis załaduje Twoje reguły i dostosuje je, kiedy serwer zacznie działać.
Zapisywanie aktualizacji
Jeśli kiedykolwiek zaktualizujesz swoją zaporę sieciową i zechcesz zachować zmiany, będziesz musiał zapisać swoje reguły Iptables.
Zapisz swoje reguły zapory sieciowej, używając tej reguły:
sudo invoke-rc.d iptables-persistent save
Wnioski
Teraz powinieneś mieć dobry punkt startowy, jeśli chcesz stworzyć swoją zaporę sieciową, która ma odpowiadać Twoim potrzebom. Istnieje wiele usług zapory sieciowej i niektóre z nich mogą być prostsze, ale iptables
jest dobrym narzędziem do nauki, ale tylko dlatego, że odkrywa on niektóre zasadnicze struktury filtrów sieciowych i ponieważ jest obecny w tak wielu systemach operacyjnych.