VPN kojarzony jest głównie z zastosowaniami biznesowymi gdzie za jego pośrednictwem łączy się oddalone od siebie sieci firmowe jak również z usługami anonimizującymi pozwalającymi na ukrycie tożsamości. Jest to również dobre narzędzie do szyfrowania przesyłanych informacji. W odróżnieniu od tunelowania SSH czy proxy umożliwia przekierowanie całego ruchu IP wykorzystując tylko jeden port do komunikacji klient-serwer. Jest to zatem doskonała recepta na publiczne hot spoty i ograniczenia napotykane w zaporach ogniowych. Dodatkowo, mając jedynie komputer z publicznym adresem IP, można korzystać z takiej usługi za darmo, budując ją w oparciu o otwarte oprogramowanie OpenVPN.

Konfiguracja OpenVPN - tunel VPN

Jako przykładową konfigurację użyjemy serwera z systemem GNU/Linux oraz klienta z systemem Windows oraz Linux. Wybór pomiędzy metodami uwierzytelniania i trybem przekazywania pakietów jest pozostawiony użytkownikowi.

Instalacja

Zarówno klient jak i serwer OpenVPN składają się na ten sam pakiet. Kod źródłowy można pobrać z openvpn.net, lub też ściągnąć i zainstalować bezpośrednio z repozytoriów. Po stronie serwera potrzebujemy również pakietu bridge-utils, jeśli chcemy używać trybu mostkowego(tap), zamiast routowania(tun).

Wersja dla Windows także zawiera serwer i klient w jednym, oraz dodatkowo nakładkę graficzną (OpenVPN GUI), która pozwala na łatwe przełączanie się między profilami połączeń. Sama instalacja nie powinna sprawiać wielu problemów, przechodzimy zatem do konfiguracji.

Konfiguracja

OpenVPN jest uruchamiany w trybie serwera, albo w trybie klienta, w zależności jaki plik konfiguracyjny podamy mu jako parametr. W przypadku systemów Windows pliki konfiguracyjne mają rozszerzenie .ovpn i znajdują się w C:\Program Files\OpenVPN\config, w przypadku systemów Unix domyślnie jest to .conf i katalog /etc/openvpn. Tuż po instalacji katalogi te są puste i należy utworzyć pliki konfiguracyjne ręcznie (lub posłużyć się plikami przykładowymi ze strony OpenVPN: server.conf, client.conf, które stanowią dobry punkt startowy). Dwie główne decyzje jakie należy podjąć, to metoda uwierzytelniania oraz wybór pomiędzy trybem routowania oraz mostka (bridge).

Przykładowy plik konfiguracyjny (dla klienta – client.conf/ovpn)

client #wskazuje że uruchamiamy openvpn jako klient
dev tun #wykorzystujemy tryb routowania(tun) lub bridge(tap)
proto udp #protokół udp (domyślnie) lub tcp
remote hostname.com 1194 #adres serwera, ip lub dns, oraz port (1194 domyślnie)
ca ca.crt #weryfikacja z użyciem certyfikatów
cert client.crt
key client.key

Przykładowy plik konfiguracyjny (dla serwera – server.conf/ovpn):

#wskazujemy ze openvpn ma być uruchomiony jako serwer w trybie tun
# z podsiecią łączącą 10.8.0.0/24 oraz weryfikować użytkowników w oparciu o certyfikaty
dev tun
port 1194
proto udp
server 10.8.0.0 255.255.255.0
ca ca.crt #weryfikacja z uzyciem certyfikatów
cert server.crt
key server.key
dh dh1024.pem

W dalszej części artykułu zajmiemy się uwierzytelnianiem oraz trybem routowania.

Uwierzytelnianie

OpenVPN oferuje kilka metod uwierzytelniania użytkowników, najczęściej spotykane to z użyciem pliku klucza (identycznego dla klienta i serwera) oraz z użyciem certyfikatów (Public Key Infrastructure – PKI). Użycie pliku klucza jest najprostszym i najszybszym rozwiązaniem, ale ma również pewne wady. Jego użycie ogranicza się praktycznie do jednego urządzenia-klienta, a w przypadku przejęcia klucza (który po stronie klienta trzymany jest w formie niezaszyfrowanej), oznacza ryzyko rozkodowania transmisji. Wymaga też, by klucz został dostarczony do klienta w bezpieczny sposób, tj nie ma możliwości wygenerowania go lokalnie (w przypadku PKI jest to możliwe). Użycie pliku klucza ma zatem uzasadnienie, gdy:

  • poza nami nikt nie będzie się łączył do naszej sieci
  • podłączamy się z zaufanej maszyny
  • chcemy w sposób szybki i prosty skonfigurować działającą sieć

Całość sprowadza się do wykonania polecenia (na serwerze bądź kliencie) openvpn --genkey --secret static.key, a następnie skopiowania wynikowego pliku na maszynę klienta i serwera. Do pliku konfiguracyjnego obu stron należy dodać linijkę:

secret sciezka_do_static.key

która wskazuje na lokalizację pliku klucza.

Uwierzytelnianie przy użyciu certyfikatów, jest ciut bardziej skomplikowane i wymaga pewnego przygotowania. Sprowadza się do wygenerowania głównego certyfikatu oraz klucza (root CA), w oparciu o które będziemy mogli generować certyfikaty dla serwerów i klientów. Ma to uzasadnienie, gdy chcemy dokładnie weryfikować czy maszyna, z którą się łączymy jest tą, za którą się podaje oraz daje możliwość większej kontroli nad każdym z klientów z osobna (w tym odwoływanie dostępu, bez konieczności przebudowy całej infrastruktury). Nie wymaga ono również bezpiecznego połączenia między klientem a serwerem w celu dostarczenia plików klucza – klient sam generuje swój klucz i wysyła prośbę do serwera głównego by ten podpisał jego certyfikat. Warto zatem użyć tej metody gdy:

  • poza nami ktoś jeszcze będzie korzystał z naszego vpn-a
  • potrzebujemy większego poziomu bezpieczeństwa (np. możliwość zablokowania klucza w razie jego utracenia)
  • klucz klienta nie może zostać dostarczony w bezpieczny sposób (brak bezpiecznego połączenia)

Zaczynamy od skopiowania skryptów powłoki które znacznie ułatwiają cały proces

cp -R /usr/share/doc/openvpn/examples/easy-rsa/2.0/ /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa

(ścieżki mogą się różnić – w zależności od użytej dystrybucji)

Następnie edytujemy plik vars i podmieniamy domyślne wartości które mają być widoczne w certyfikatach (warto to zrobić teraz by uniknąć ponownego wpisania ich później). Możemy też zwiększyć długość klucza RSA z 1024 (domyślne) do 2048 bitów.

Po edycji wykonujemy polecenia:

source ./vars
./clean-all

Powyższe polecenia wygenerują klucze oraz certyfikaty dla maszyny certyfikującej (CA), serwera oraz jednego klienta. W każdym przypadku można zaakceptować domyślne wartości i wybierając na końcu opcję zatwierdzenia certyfikatów ("Sign the certificate? [y/n]" oraz "x out of x certificate requests certified, commit? [y/n]"). Istotne jest by używać unikalnych nazw dla serwerów/klientów (tutaj użyto fraz „server” oraz „client1” ). Ostatnie polecenie wygeneruje plik zawierający dane przeznaczone dla protokołu Diffiego-Hellmana.

./build-ca
./build-key-server server
./build-key client1
./build-dh

W wyniku powyższych poleceń zostanie utworzony katalog keys, w którym będą się znajdowały pliki certyfikatów (z rozszerzeniem .crt) i prywatne pliki kluczy (z rozszerzeniem .key) oraz plik dfX.pem (gdzie X to domyślnie 1024 bity). Pliki .csr odnoszą się do sytuacji gdy generujemy plik klucza z dala od maszyny certyfikującej (posiadającej plik ca.key), czyli w sytuacji gdy nie mamy możliwości dostarczenia klucza do serwera/klienta w bezpieczny sposób. W tym przypadku robimy wszystko na tej samej maszynie, więc nie są one nam potrzebne (w pewnym sensie nie korzystamy tutaj z tego przywileju jaki daje nam architektura PKI).

Następnie dostarczamy odpowiednie pliki do odpowiednich urządzeń:

  • do serwera: ca.crt, dhX.pem, Server.crt, Server.key
  • do maszyny podpisującej certyfikaty (w naszym przypadku również jest to serwer): ca.key
  • do klienta/ów: ca.crt , clientX.crt, clientX.key

Pliki certyfikatów (.crt) mogą być publicznie dostępne, pliki kluczy (.key) są przeznaczone tylko dla tego dla kogo zostały wygenerowane, i powinny być trzymane w ukryciu (a zwłaszcza plik ca.key)

Na koniec umieszczamy odpowiednie wpisy w plikach konfiguracyjnych

  • po stronie serwera (w pliku server.conf)
    ca sciezka_do_ca.crt
    cert sciezka_do_server.crt
    key sciezka_do_server.key
    dh sciezka_do_dh1024.pem
  • po stronie klienta (w pliku client.conf/client.ovpn)
    ca sciezka_do_ca.crt
    cert sciezka_do_client.crt
    key sciezka_do_client.key

Jeśli zajdzie potrzeba odwołania któregoś z podpisanych certyfikatów wystarczy wykonać

./revoke-full <identyfikator klienta>

w wyniku którego do katalogu keys zostanie zapisany plik ctr.pem, do którego ścieżkę należy podać w konfiguracji serwera: crl-verify crl.pem

dev tun vs dev tap

OpenVPN umożliwia nam podłączenie się do naszej sieci na dwa sposoby – w trybie routowania (tun) oraz w trybie mostkowania, czyli bridge (tap).

Konfiguracja OpenVPN - bridge

W trybie bridge (tap) jesteśmy podłączeni bezpośrednio do sieci LAN serwera, otrzymując IP z tej samej podsieci co reszta urządzeń. Wymaga to zestawienia mostka pomiędzy wirtualnym interfejsem OpenVPN (tap0) oraz interfejsem mającym dostęp do sieci LAN serwera (np eth0). Pozwala na to m.in. narzędzie brctl, znajdujące się w pakiecie bridge-utils.

Konfiguracja OpenVPN - route

W trybie routowania (tun) tworzona jest osobna prywatna podsieć, która łączy się z siecią po stronie serwera, ustalając statyczny routing. Po podłączeniu otrzymujemy adres z innej podsieci, niż ta docelowa, przez co przynależymy do osobnej domeny rozgłoszeniowej. Jest to z reguły prostsze i mniej kłopotliwe rozwiązanie, aniżeli ustanawianie mostka, ale powoduje też, że takie usługi jak otoczenie sieciowe lub zasoby dyskowe Windows nie będą dla nas dostępne (za wyjątkiem samby, która umożliwia ominięcie tego ograniczenia).

Jeśli nie potrzebujemy dostępu do zasobów w ramach domeny rozgłoszeniowej i nie wykorzystujemy OpenVPN do uruchamiania usług opartych LAN (np. serwerów gier), to lepiej korzystać z dev tun (również z punktu widzenia bezpieczeństwa routing, umożliwia większą kontrolę nad klientami). Do celów przedstawionych w artykule (użycie tunelu VPN do szyfrowania transmisji), tryb routowania (tun) jest wystarczający.

Jeśli chcemy pracować w trybie routowania w konfiguracji serwera musimy zadeklarować:

dev tun
server 10.8.0.0 255.255.255.0

gdzie 10.8.0.0/24 będzie stanowić podsieć, do której będą przynależeć klienci. Istotne jest, by podsieć ta była unikalna, tj nie może się pokrywać z tą, do której aktualnie przynależymy (kawiarenka, hot spot), inaczej wystąpi konflikt, przy routowaniu pakietów.

Po stronie klienta wystarczy deklaracja

dev tun

Następnie musimy włączyć przekazywania pakietów między interfejsami (pomiędzy eth0 a tun0). W tym celu wykonujemy polecenie:

echo 1 > /proc/sys/net/ipv4/ip_forward

Zmiana ta będzie brana pod uwagę, do momentu restartu systemu. Aby zastosować ją na stałe należy edytować plik /etc/sysctl.conf oraz zmienic wartość net.ipv4.ip_forward na 1.

Dodatkowo musimy zadbać aby pozostałe hosty w sieci wiedziały jak się z nami komunikować. Ponieważ używamy dodatkowej sieci łączącej (10.8.0.0) musimy ustanowić statyczny routing na bramie sieciowej (np routerze) kierujący do sieci vpn (10.8.0.0) przez maszynę z uruchomionym demonem openvpn. Krok ten wykonujemy tylko jeśli serwer openvpn i brama domyślna dla innych urządzeń (router) nie są tym samym urządzeniem. Alternatywnie można posłużyć się NAT (o którym za chwilę).

W sytuacji, gdy chcemy zastosować mostek (dev tap), musimy mieć zainstalowany w systemie pakiet bridge-utils (a konkretnie mieć do dyspozycji narzędzie brctl). Proces tworzenia i usuwania mostka możemy zautomatyzować, korzystając ze skryptu znajdującego się na stronie OpenVPN. W skrypcie startowym należy podmienić adresy IP, na odpowiadające im ustawienia interfejsu eth0 (przyłączonego do sieci LAN po stronie serwera, chcemy by br0 „przejął” adres IP i maske eth0). W skrypcie usuwającym mostek, zalecałbym również dodanie na końcu:

service networking restart

Jest to istotne, gdyż skrypt ten usunie adresy IP interfejsów eth0 oraz tap0, połączy je (utworzy most) w jeden interfejs br0 (bridge), a przy usuwaniu nie przywraca adresacji do pierwotnej postaci (przez co możemy utracić połączenie).

W pliku konfiguracyjnym serwera podajemy:

dev tap0
server-bridge 192.168.55.10 255.255.255.0 192.168.55.30 192.168.55.40

gdzie pierwszy adres odnosi się do interfejsu br0, a dwa ostatnie adresy to przedział z jakiego przydzielony zostanie adres IP klientom.

Na koniec dodajemy regułki do firewalla, pozwalające na przesył pakietów:

iptables -A INPUT -i tap0 -j ACCEPT
iptables -A INPUT -i br0 -j ACCEPT
iptables -A FORWARD -i br0 -j ACCEPT

Procedura uruchamiania OpenVPN, wygląda w tym przypadku następująco:

  1. wykonujemy skypt start.sh by utworzyć mostek (możemy chwilowo utracić połączenie)
  2. uruchamiamy usługę OpenVPN (/etc/init.d/openvpn start)
  3. zatrzymujemy OpenVPN (/etc/init.d/openvpn stop)
  4. wykonujemy skrypt stop.sh by usunąć mostek

Dodatkowe ustawienia

Jest kilka ustawień, które warto uwzględnić w konfiguracji (klienta i serwera), by poprawić ogólną wydajność i bezpieczeństwo.

  • persist-tun – zachowuje i uwzględnia dodatkowe parametry między restartami usługi
  • persist-key
  • keepalive 10 60 – wysyła ping co 10 sekund z timeout=60s, zmniejsza podatność na przerwanie połączenia
  • comp-lzo – włącza kompresje, zmniejsza zuzycie transferu
  • remote-cert-tls server – ustawiamy tylko w pliku klienta – sprawdza czy pole nsCertType w certyfikacie serwera jest ustawione na „server” (wybór dokonywany przy generowaniu certyfikatu serwera), podnosi bezpieczeństwo
  • Z poniższej opcji można skorzystać jeśli już korzystamy z weryfikacji opartej na certyfikatach. Wykorzystuje ona ten sam mechanizm i jest generowana tak samo jak statyczny plik klucza, dodatkowo zwiększając ochronę przed atakami DoS oraz skanowaniem portów:
    • tsl-auth ta.key 0 – dla serwera
    • tsl-auth ta.key 1 – dla klienta
  • user nobody – zmniejsza uprawnienia procesu, tylko systemy unixowe
  • group nobody
  • cipher AES-256-CBC – jeśli chcemy zwiększyć długość symetrycznego klucza użytego przy szyfrowaniu możemy użyć algorytmu AES z kluczem 256 bitowym

Przekierowywanie pakietów IP przez VPN

Zbliżamy się do sedna artykułu, czyli przekierowywania całego ruchu przez tunel VPN. Na tym etapie powinniśmy mieć już w pełni działające połączenie do serwera (działające pingi), a na wyjściu do Internetu zaszyfrowane pakiety. Konfiguracja jest identyczna dla trybu bridge (tap) jak i routingu (tun).

Dodajemy do pliku server.conf

push "redirect-gateway def1"
push "dhcp-option DNS 8.8.8.8"     #serwery dns google
push "dhcp-option DNS 8.8.4.4"

Instrukcja redirect-gateway modyfikuje tablice routingu w systemie tak, by trasa przez tunel VPN miała niższą metrykę niż na zwykłym interfejsie eth0 (dzięki czemu pakiety będą przekierowywane przez tun/tap).

Na systemie Windows z włączonym UAC, klient musi mieć podniesione uprawnienia (zostać uruchomionym z prawami administratora), by instrukcja redirect-gateway odniosła skutek.

Jeśli korzystamy z trybu routowania (tun) musimy również ustalić translację adresów (NAT) na serwerze. Można to zrobić następująco

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

W większości przypadków, jeśli modyfikujemy plik konfiguracyjny OpenVPN, musimy uruchomić ponownie usługę. Jeśli uruchomiliśmy ją wcześniej, należy wykonać ponowny rozruch.

To tyle, jeśli chodzi o konfigurację. Po wejściu na dowolną stronę sprawdzającą adres IP, powinniśmy być identyfikowani jako serwer a nie komputer, z którego nawiązujemy połączenie. Dodatkowo cały ruch na odcinku klient-serwer jest szyfrowany domyślnie przy użyciu algorytmu Blowfish 128bit.

Wydajność

Krótki test wydajności mający poglądowo pokazać, wpływ tunelowania VPN na prędkość i stabilność przesyłu danych.

Do testów wykorzystałem instancję EC2w chmurze Amazonu, z dostępem do jednego rdzenia procesora Intel Xeon E5430 @2.66Ghz oraz 600MB pamięci RAM (dostępnej dla użytkownika). Serwer oparty na Ubuntu Server Cloud Guest 11.04 64bit z lokalizacją w Irlandii. Testowałem z peryferiów Łodzi, mały lokalny ISP, Internet 6Mb/1Mb

Wykorzystałem trzy scenariusze, jeden stanowiło standardowe połączenie z Internetem (bez vpn), drugi przy przekierowywaniu całego ruchu przez serwery Amazon bez kompresji comp-lzo, trzeci z kompresją. Pobierałem dwa pliki – instalator Mozilla Firefox o ze strony mozilla.org (16.5MB) oraz BitDefender Internet Security 2012 ze strony dobreprogramy.pl (233mb). Statystyki zmierzyłem wgetem. Zmierzyłem też czas odpowiedzi na ping do 4 różnych serwisów (rozmiar pinga standardowy, 10 próbek, podana średnia) oraz 100 pingów do jednego serwisu (celem sprawdzenia niezawodności).

Konfiguracja OpenVPN - pobieranie plików

W przypadku BitDefendera różnica prawie 170kB/s może wynikać z lokalizacji serwera hostującego plik (Polska) oraz kraju do jakiego jest on pobierany (Irlandia). Natomiast w przypadku Firefoxa różnica między pobieraniem z kompresją włączoną, a wyłączoną może być spowodowana charakterystycznym sposobem pobierania – przy kompresji włączonej prędkość pobierania rosła w określonym tempie, a przy wyłączonej od początku ściągane było z maksymalna prędkością. Ponieważ plik był mały, prędkość pobierania nie zdążyła się „rozpędzić”. Test powtórzyłem dla pewności trzy razy – wyniki były podobne.

Konfiguracja OpenVPN - ping

W przypadku pinga wpływ tunelowania powoduje ponad dwukrotny wzrost opóźnienia, ale tak jak wyżej wspomniano – głównym czynnikiem jest tutaj lokalizacja serwera VPN. Jeśli chodzi o komfort przeglądania stron, nie było widać znaczących różnic w szybkości pobierania i prezentowania www, czy też przeglądaniu klipów na Youtube.

Przeprowadziłem również test wysłania 100 ping-ów w domenę Google.pl dla trzech scenariuszy. Każdy z nich posiadał 100% skuteczność oraz średni czas taki jak na wykresie.

Troubleshooting OpenVPN

Oto kilka błędów na które się natknąłem i które mogą się wam przydarzyć w trakcie instalacji / korzystania z OpenVPN:

  • Znaczna część problemów z połączeniem dotyczy ustawień firewalla. Należy sprawdzić czy wirtualny interfejs nie jest filtrowany oraz czy nie są blokowane porty wychodzące dla używanej konfiguracji (domyślnie jest to port 1194 UDP)
  • Jeśli przy uruchamianiu vpn-a otrzymujemy błąd:
    Starting virtual private Network demon : Server failed!
    warto zajrzeć do sysloga po więcej informacji. (/var/log/syslog). W większości przypadków błąd ten dotyczy literówek w plikach konfiguracyjnych lub odnoszeniu się do nieistniejących interfejsów (tap0/tun0).
  • errno=2 lub errno=13 w syslogu – błąd ten może występować w przypadku systemów uruchamianych na OpenVZ. OpenVPN może mieć problem z utworzeniem interfejsu wirtualnego tun/tap. Należy wtedy zrobić to ręcznie korzystając z poniższych poleceń:
    • mkdir –p /dev/net
    • mknod /dev/net/tun c 10 200
    • chmod 600 /dev/net/tun

    Poleceniem cat /dev/net/tun sprawdzamy czy wszystko przebiegło pomyślnie.

  • Jeśli otrzymamy wynik cat: /dev/net/tun: No such device najlepiej skontaktować się z dostawcą VPS po informację czy tworzenie interfejsów tun/tap jest u nich dozwolone.
  • W przypadku problemów z przekierowywaniem pakietów warto sprawdzać systemową tablice routingu by mieć pewność że pakiety są wysyłane tam gdzie powinny (polecenie route pod Unix/Windows). Przykładowa sytuacja – mamy działajace połączenie do interfejsów serwera ale sieć wewnętrzna (oraz Internet jeśli przekierowujemy cały ruch) jest dla nas niedostępna (timeout). Oznaczać to może brak routingu w sieci – należy wtedy ustalić translację adresów NAT lub dodać regułki ręcznie na bramie domyślnej w sieci serwera.