VPN [LINUX/*BSD] <-> Windows NT/2K/XP     HOWTO


Celem niniejszego HOWTO jest podanie działającego przykładu VPNa między bramą postawioną na linuxie (wzgl. BSD), a klientem Windowsowym.
Problem do rozwiązania: coraz większa liczba 'zdalnych pracowników' musi mieć dostęp z zewnątrz do coraz większej ilości danych firmowych - znajdujących się na lokalnych serwerach w firmie. Położenie jak i adres IP pracowników jest nieznany, często łączą się zza jakiejś maskarady w sieci osiedlowej czy z innych podejrzanych miejsc.

Dobrym rozwiązaniem powyższego problemu jest zestawienie połączenia VPN między klientem, a routerem firmowym (bramką VPN). Połączenie to zapewnia szyfrowany tunel z siecią wewnętrzną firmy, dzięki czemu aplikacje klienckie będą mogły pracować tak, jakby osoba była fizycznie w firmie. Cały ruch warstwy transportowej (aplikacji klienckich) jest enkapsulowany (opakowywany "warstwą ochronną") i przez internet "leci" w postaci pakietów UDP. Po stronie bramy VPN następuje proces odwrotny - dekapsulacja, czyli zdejmowanie warstwy nałożonej w procesie tunelowania. Pokazuje to załączony schemat.

Tyle teorii, w praktyce dzięki enkapsulacji można przez internet przesłać protokoły nierutowalne (np. IPX*, NetBEUI itp), a co najważniejsze w sposób bezpieczny

OpenVPN - openvpn.sourceforge.net

Zdecydowałem się na wybór pakietu OpenVPN, gdyż jego instalacja nie jest trudna, a możliwości całkiem dobre. Co najważniejsze, pakiet działa też pod systemami Windows, niestety w chwili pisania tego tekstu (grudzien 2003), są wersje tylko pod NT4/2K/XP. Być może niebawem wyjdą wersje pod Win9x/Me

Instalacja - Linux/BSD:

	    1) sciągnij najnowsze źródła stabilnej wersji. Uwaga - program 
	    spakowany jest jakimś kosmicznych gzipem. Wstyd się przyznać,
	    ale ja to rozpakowałem pod Windows Commanderem, następnie 
	    spakowałem do 'zwykłego' tgz i przesłałem na serwer :)
	    2) ./configre && make && make install
	    Pod linuxem można dodać też opcję --enable-pthread, bo jak piszą:
	    --enable-pthread        Compile pthread support for improved SSL/TLS latency
	    jeśli nie masz biblioteki LZO, to musisz wyłączyć obsługę 
	    kompresji  --disable-lzo, ale lepiej ją doinstalować:
	    http://www.oberhumer.com/opensource/lzo/
	    Założyłem tutaj, że używasz linuxa na kernelu 2.4, w przeciwnym
	    razie musisz poczytać dokładnie proces instalacji na kernelu 2.2
	    (na stronie głównej projektu).
	    Oczywiście musi być też zainstalowany OpenSSL, ale to chyba każdy ma.
	

Konfiguracja:

	    Pierwszą rzeczą na jaką musimy się zdecydować, to sposób autoryzacji. Są tutaj dwa rozwiązania:
	    1 - prostsze - współdzielony klucz (Pre-Shared Key)
	    2 - trudniejsze - rozwiązanie oparte o SSL/TLS - certyfikaty i klucze RSA
	
Rozwiązanie oparte o współdzielony klucz

Musisz wygenerować klucz i umieścić go po obu stronach tunelu (na bramie i u klineta/ów). Łatwo się domyśleć co się stanie gdy któremuś z pracowników zginie laptop... generujemy: openvpn --genkey --secret static.key Dalej musisz przegrać (w sposób bezpieczny :) ten klucz na laptopa zdalnego pracownika.
Jeśli wystarczy Ci rozwiązanie oparte o klucz współdzielony - możesz przeskoczyć od razu do działu konfiguracja OpenVPN

Rozwiązanie oparte o certyfikaty

Tutaj jest ostra jazda dla osób nieznających tematki SSL, dlatego właśnie postanowiłem napisać to HOWTO :)
Jeśli znasz dobrze tematykę SSL albo preferujesz rozwiązanie oparte o klucz współdzielony - możesz opuścić poniższe wypociny dotyczące certyfikatów i przekoczyć od razu do działu konfiguracja OpenVPN

Musimy wyróżnić następujące pojęcia:

Zakładam, że wystawcą certyfikatu chcesz być Ty sam (w komercyjnych rozwiązaniach trzeba dać sobie podpisać certyfikat przez "zaufanego" wystawcę - np. Thawte, dzięki czemu inni będą mieli pewność, że Ty to naprawdę Ty :) (ma to większe znaczenie dla certyfikatów wystawianych dla serwerów WWW)

przygotowanie OpenSSL

znajdź plik openssl.cnf - będzie on albo w /etc/ssl/ - jeśli masz OpenSSL'a instalowanego razem z dystrybucją (Slack tak ma), albo gdzieś /usr/local, jeśli kompilowałeś OpenSSLa sam.
Należy podać właściwy katalog dla zmiennej dir. Ja założyłem sobie katalog /keys i tam OpenSSL przygotowuje mi wszystkie pliki:
	    [ CA_default ]

	    dir             = /keys                 # Where everything is kept
	    certs           = $dir/certs            # Where the issued certs are kept
	    crl_dir         = $dir/crl              # Where the issued crl are kept
	    database        = $dir/index.txt        # database index file.
	    new_certs_dir   = $dir/newcerts         # default place for new certs.

	    certificate     = $dir/cacert.pem       # The CA certificate
	    serial          = $dir/serial           # The current serial number
	    crl             = $dir/crl.pem          # The current CRL
	    private_key     = $dir/private/cakey.pem# The private key
	    RANDFILE        = $dir/private/.rand    # private random number file
	
Ważnym jest żebyś założył w swoim katalog $dir (u mnie /keys) podkatalogi crl/   private/  certs/  newcerts/  oraz stworzył następujące pliki:
	    touch /keys/index.txt
	    echo 00 > /keys/serial
	
Możesz też w openssl.cnf przypisać domyślne wartości zmiennych, o które pyta OpenSSL podczas generowania certyfikatów, zaoszczędzisz później trochę czasu (nie musząc wpisywać kilka razy tego samego). W tym celu na końcu pliku odszukaj zmiennych _default:

	    [ req_distinguished_name ]
	    countryName                     = Country Name (2 letter code)
	    countryName_default             = PL      
	    stateOrProvinceName             = State or Province Name (full name)
	    stateOrProvinceName_default     = Poland
	    localityName                    = Locality Name (eg, city)
	    localityName_default            = Gliwice
	

generacja kluczy

generujemy klucz prywatny wystawcy certyfikatu cakey.pem

	    openssl genrsa -des3 -out private/cakey.pem 1024
	
Należy tu podać hasło - będzie nam później potrzebne przy wystawianiu certyfikatow innym jednostkom.
Teraz generujemy certyfikat wystawcy - czyli certyfikat Root CA, zeby za rok się nie denerwować, dajmy od razu ze 5 lat ważności:
	    openssl req -new -x509 -days 1825 -key private/cakey.pem -out cacert.pem
	
Jako hasło podajemy nasze hasełko klucza prywatnego Root CA. Openssl zapyta o różne dziwne rzeczy - najlepiej podawać zgodnie z pytaniami. Na pytanie 'Common Name' - podaj nazwę firmy lub jakiś dowolny ciąg znaków. Na pytanie o e-mail też nie musisz podawać swojego prawdziwego...

generujemy klucz i certyfikat dla bramy VPN:

	    openssl genrsa -des3 -out private/gwkey.pem 1024
	
Problem z hasłem dla klucza bramy polega na tym, że przed każdym zestawieniem tunela trzeba będzie podać hasło (po stronie bramy !, a nie da się go pobrać z pliku, przynajmniej nie widzę takiej opcji). Jeśli chcesz uniknąć pytania, to możesz ściągnąć hasło z klucza. Zrobimy to jednak na samym końcu

Dalej tworzymy wniosek (do Root CA) o wydanie nam certyfikatu:

	    openssl req -new -key private/gwkey.pem -out gwreq.pem
	
Potwierdzamy hasłem klucza prywatnego BRAMY
W pytaniu o 'Common Name' możesz podać nazwę firmy albo inną swoją nazwę. Będzie tam też pytanie o jakieś dodatkowe atrybuty -- zostawiamy puste.

Teraz jako Root CA wydajemy bramie certyfikat:

	    openssl ca -notext -in gwreq.pem -out gwcert.pem
	    {tutaj podajemy hasło klucza prywatnego Root CA - te pierwsze hasło w ogóle)
	

Z ważnych plików mamy już:

Czyli brakuje nam jeszcze klucza prywatnego usera i podpisanego dla niego (przez CA) certyfikatu (krótko userkey.pem i usercert.pem).
Procedura jest dokładnie taka sama jak dla bramy VPN. Nie ściągałbym jednak później hasła z kluczy userów - nawet w przypadku utraty komputera, do zestawieniem tunela trzeba jeszcze będzie podać hasło (hasło klucza prywatnego usera).
	    generujemy klucz prywatny usera:
	    openssl genrsa -des3 -out private/userkey.pem 1024
	    
	    dalej wystawiamy wniosek o wydanie certyfikatu:
	    openssl req -new -key private/userkey.pem -out userreq.pem
	    (teraz należy podać hasło klucza prywatnego usera - te powyższe)

	    następnie mając przygotowany wniosek (userreq.pem) podpisujemy go jako CA:
	    openssl ca -notext -in userreq.pem -out usercert.pem

	    (teraz należy podać oczywiście hasło klucza wystawcy CA - czyli to pierwsze hasełko w ogóle)
	    Można rozważyć opcję skrócenia czasu ważności kluczy userów do np. kilku miesięcy 
	    (ustawia to przełącznik enddate przy podpisie przez CA - format YYMMDDHHMMSSZ)
	
	    Ważność certyfikatu (validity) możemy zawsze sprawdzić poleceniem:
	    openssl x509 -noout -text -in user.crt
	

Huh mamy już wszystkie potrzebne pliki:

	    cakey.pem , cacert.pem , gwkey.pem , gwcert.pem , userkey.pem , usercert.pem
	
Teraz możemy ściągnąć hasło z klucza bramy:
	    openssl rsa -in private/gwkey.pem -out private/gwkey.pem_bezhasla
	    oczywiście operacja się uda tylko pod warunkiem podania poprawnego hasła dla gwkey.pem
	
Tak naprawdę cakey.pem jest potrzebny tylko do podpisywania nowych wniosków. Do samego działania tunela nie jest on potrzebny.
Pliki *req.pem (wnioski) możesz skasować - nie są już potrzebne.



KONFIGURACJA OpenVPN

Zasadniczo OpenVPN może działać w dwóch trybach: Jak łatwo się domyśleć różnica polega w tym co przekazywane jest przez zestawiony tunel. W trybie bridga "leci" wszystko - łącznie z broadcastami. Dla aplikacji warstw wyższych tunel jest zupełnie przeźroczysty. Nadaje się do transportowania IPX-a po IP. Do wad należy oczywiście znacznie większy ruch - w zależności od wielkości sieci firmowej, broadcasty potrafią zatkać słabe połączenie PPP.
W trybie routera 'dev tun' zestawiony kanał działa jak normalny router. Zestawiane jest połączenie punkt-punkt (na wirtualnych interfejsach tun) i w celu dostępu do zdalnej sieci należy ustawić odpowiednio trasę routingu:
	    route add siec_firmowa MASKA gw ip_virtualne_bramy_vpn
	
Wydajniejsze jest oczywiście połączenie typu router, niemniej w niektórych przypadkach korzystniejsze może okazać się bridgowanie.

router - czyli dev tun
po pierwsze sprawdź czy masz załączony forwardnig, bo przez tą drobnostkę można stracić dużo czasu:

	    echo 1 > /proc/sys/net/ipv4/ip_forward
	
następnie załaduj driver obsługi tunela:
	    modprobe tun
	
Na początek konfiguracja przy użyciu współdzielonego klucza:

Przygotowujemy konfiga np. w /etc/openvpn/config-router
Przykładowa klasa IP 10.3.0.0/24 dla potrzeb tunelu może być oczywiście inna. Jeśli po drugiej stronie istnieje sieć o takiej puli adresowej to z całą pewnością musisz wykorzystać inną pulę na potrzeby tunelu.

	    # przykładowa konfiguracja przy użyciu klucza współdzielonego
	    # plik konfiguracyjny po stronie bramy VPN
	    # Brak wartości remote oznacza, że dopuszczamy każdy IP po drugiej stronie
	    dev tun
	    tun-mtu 1500
	    # ifconfig local_ip remote_ip
	    ifconfig 10.3.0.1 10.3.0.2
	    ; port 5000
	      user nobody
	      group nobody
	      comp-lzo
	      
	      ; ping 15
	      ; ping-restart 45
	      ; ping-timer-rem
	      ; persist-tun
	      ; persist-key
	    
	       verb 3
	       secret /etc/openvpn/secret.key
	       ; eof
	   
Po stronie klienta plik wygląda następująco:
	    dev tun
	    tun-mtu 1500
	    remote 157.158.1.3  // faktyczny IP bramy VPN !
	    # ifconfig local_ip remote_ip
	    ifconfig 10.3.0.2 10.3.0.1    // uwaga - odwrotnie niż po stronie Bramy !
	    ; port 5000
	      user nobody
	      group nobody
	      comp-lzo
	      
	      ; ping 15
	      ; ping-restart 45
	      ; ping-timer-rem
	      ; persist-tun
	      ; persist-key
	    
	       verb 3
	       secret c:\progra~1\openvpn\config\secret.key
	       ; eof
	   
Oczywiście dostęp do pliku klucza powinien mieć tylko root. Opcje 'ping' są używane w celu sprawdzenia czy 'druga strona' jeszcze "żyje" - przydatne w przypadku gdy klient często łączy się na chwilę i rozłącza (laptopowcy).

konfiguracja oparta o certyfikaty

Tutaj należy wyróżnić serwera i klienta. Założyłem że serwerem będzie brama VPN po stronie firmy. Przed przystąpieniem do edycji konfiga musimy wygenerować jeszcze jeden plik (Diffie Hellman parameters)
	       openssl dhparam -out dh1024.pem 1024
	   
Mając już wszystkie pliki kluczy kopiujemy do jednego podkatalogu np. /etc/openvpn/certs/ i przystępujemy do edycji konfiga:
	       # przykładowa konfiguracja przy użyciu certyfikatów. Zwróc uwagę
	       # odróżnienie klienta i serwera.
	       # plik konfiguracyjny serwera (bramy VPN)
	       dev tun
	       tun-mtu 1500
	       ifconfig 10.3.0.1 10.3.0.2

	       ; port 5000

		user nobody
		group nobody

	       comp-lzo

		  ; ping 15

		  ; ping 15
		  ; ping-restart 45
		  ; ping-timer-rem
		  ; persist-tun
		  ; persist-key

		verb 4
		tls-server
		dh /etc/openvpn/certs/dh1024.pem
		
		# certyfikat wystawcy (CA)
		ca /etc/openvpn/certs/cacert.pem

		# certyfikat bramy
		cert /etc/openvpn/certs/gwcert.pem

		# klucz prywatny bramy 
		key /etc/openvpn/certs/gwkey.pem
		# lub /etc/openvpn/certs/gwkey.pem_bezhasla
		;eof
	    
Konfiguracja po stronie klienta wygląda następująco:
		remote IP_SERWERA_VPN   # faktyczne "zewnętrzne" IP Internetowe Bramy VPN
		port 5000
		dev tun
		tun-mtu 1500
		ifconfig 10.3.0.2 10.3.0.1

		tls-client

		 Certificate Authority file
		 ca c:\progra~1\openvpn\config\cacert.pem
		
		 # Our certificate/public key
		 cert c:\progra~1\openvpn\config\usercert.pem
		
		 # Our private key
		 key c:\progra~1\openvpn\config\userkey.pem
		
		 ; ping-restart 60
		 ; ping-timer-rem
		 ; persist-tun
		 ; persist-key
		 ; resolv-retry 86400
		
		# # keep-alive ping
		ping 10
		
		# # enable LZO compression
		comp-lzo
		verb 4
		; eof
	    
uruchomienie tunelu
Jako pierwsze sprawdź, czy klient potrafi "pingnąć" internetowe (zewnętrzne) IP bramy z którą ma się łączyć. Jeśli nie potrafi, dalej nawet nie próbuj do czasu aż nie będzie poprawnej komunikacji przed tunelem - ja przez to straciłem 20 minut :(
uruchomienie jest banalnie proste:
		openvpn --config /etc/openvpn/config...
	    
Po stronie windowsa albo j.w. z lini komend, albo prawym klawiszem myszy kliknij na pliku konfiguracyjnym i z menu wybierz 'Start OpenVPN on this config file'
Obserwuj komunikaty, częstym błędem jest literówka w ścieżce do certyfikatów. Jeśli tunel się postawi powinno się dać pingnąć przeciwną stronę, czyli po stronie Windowsa powinno dać się pingnąć IP 10.3.0.1 - jeśli tak, to wszystko działa OK ! Żeby teraz móc dostać się do komputerów w sieci wewnętrznej po drugiej stronie bramy VPN trzeba dodać trase routingu. Zakładając, że sieć firmowa to pula 10.0.0.0/24 należy wpisać:
		; składnia unixowa
		route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.3.0.1
		; składnia windowsowa
		route add 10.0.0.0 mask 255.255.255.0 10.3.0.1
	    
Po wpisaniu powyższego powinno dać się pingować komputery w sieci wewnętrznej firmy (np. 10.0.0.5)
Żeby przy każdym zestawianiu tunela nie wpisywać ręcznie routingu da się dodać to polecenie do samego konfiga

bridgowanie
Nie dam już rady opisać dokładnie konfiguracji dla bridge'a, ale jest ona doskonale napisana na stronie głównej projektu. Napiszę tylko w skrócie jak to działa:
		`which brctl` addbr br0
		`which brctl` addif br0 eth1
		`which brctl` addif br0 tap0
		`which ifconfig` tap0 0.0.0.0 promisc up
		`which ifconfig` eth1 0.0.0.0 promisc up
	    
		; przykładowy konfig dla bridge'a po stronie bramy VPN
		dev tap0
		; zamiast local_ip remote_ip jest tylko klasa wewn. sieci
		ifconfig 10.0.0.0 255.255.255.0
		ifconfig-nowarn
		; port 5000
		user nobody
		group nobody
		comp-lzo

		ping 15
		ping-restart 45
		ping-timer-rem
		persist-tun
		persist-key
		verb 3
		; tutaj użyłem prostszej metody klucza współdzielonego, ale można
		; oczywiście użyć certyfikatów.
		secret /etc/openvpn/secret.key
	    

Główna różnica w pliku konfiguracyjnym to:

I tyle , w przypadku bridgowania nie trzeba (z założenia) ustawiać żadnych tras routingu - jesteśmy przecież wewnątrz sieci firmowej :)


Pewnie kiedyś przyjdzie moment, w którym wygaśnie twój self-signed CA.crt (certyfikat wystawcy). Wówczas przestaną działać wszystkie tunele. Możesz oczywiście wygenerować nowy CA.crt, ale wówczas musiałbyś także wygenerować nowe certyfikaty dla każdego usera.A tego raczej nie chcesz :) Poniżej podaję polecenie jak wygenerować nowy CA.crt na podstawie starego. Dzięki temu unikniesz generowania nowych certów dla userów. Jedyne co będziesz musiał zrobić, to podmienić po stronie bramy VPN plik ca.crt oraz wysłać go każdemu z użytkowników.
openssl x509 -in ca-old.crt -days 3650 -out ca-new.crt -signkey private/ca.key


linki

26.12.2003 , ^marek/(o)\rojcanet/(-)pl$