cd ~/

Home of Daniel Graf

Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

cd ~/

Home of Daniel Graf

Seiten

Suche

Blog Meta

Dynamo Dresden

Galerie

braindump:aufbau_eines_vpns_mit_openvpn

Aufbau eines VPNs mit OpenVPN

Wieso?

Mit diesem HowTo möchte ich beschreiben, wie ich mein OpenVPN eingerichtet habe, um von extern jederzeit auf die Daten meiner NAS zugreifen zu können.

Mein Heimnetzwerk 172.16.2.0/24 besteht in erster Linie aus einem Telekom Speedport Router und einem direkt daran angeschlossenen NAS, wobei diese auch mein Router, bzw. auch die Firewall für meine internen Netze ist.

Ziel soll es letztendlich sein, dass ich mich über die dynamische IP meines Internet-Anschlusses per OpenVPN auf meiner NAS einwähle, eine VPN-IP aus einem dafür vorgesehenen Netz zugeteilt bekomme und anschließend Zugriff auf z.B. Netzwerk-Freigaben oder andere Dienste meiner NAS habe.

Dabei soll die Authentifizierung am System aber zweistufig erfolgen: Sowohl ein gültiges Client-Zertifikat, als auch Username und Passwort, sind für einen erfolgreichen Login nötig.

Installation

Auf meiner NAS (Debian GNU/Linux Lenny 5.0) muss OpenVPN und OpenSSL installiert werden:

apt-get install openvpn openssl

Konfiguration

Als ersten Schritt legen wir Zertifikate an. Prinzipiell kann man dies über OpenSSL selbst tun. Allerdings ist dies nicht trivial und man muss sich in der Regel bei jeder Änderung neu einlesen.

Eine schöne Alternative bietet OpenVPN schon von Haus aus: easyrsa. easyrsa ist eine Scriptsammlung, um ein VPN, welches mit Zertifikaten betrieben wird, zu administrieren.

Unter Debian finden sich die Scripte unter /usr/share/doc/openvpn/examples/easy-rsa/2.0/ wieder. In eben diesem Verzeichnis gibt es die Datei vars, diese wollen wir editieren:

[...]
# Increase this to 2048 if you
# are paranoid.  This will slow
# down TLS negotiation performance
# as well as the one-time DH parms
# generation process.
export KEY_SIZE=2048                          # Wir sind paranoid und erhöhen den Wert auf 2048 (Bit)
[...]
# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
export KEY_COUNTRY="DE"                       # Ländercode
export KEY_PROVINCE="Sachsen"                 # Bundesland
export KEY_CITY="Dresden"                     # Stadt
export KEY_ORG="Debian-Hell.org Home-Office"  # Bezeichnung
export KEY_EMAIL="noc@debian-hell.org"        # technischer Kontakt

Die grad gesetzten Angaben werden benötigt, damit wir unsere Certificate Authority, kurz CA, aufbauen können. Diese wird letztendlich dazu gebraucht, damit wir unseren Clients (für uns) gültige Zertifikate ausstellen können.

Anschließend entfernen wir eventuell vorhandene Zertifikats-Restbestände (ACHTUNG - nur ausführen, wenn die Daten nicht mehr benötigt werden), und erstellen die CA.

./clean-all
./build-ca

Beim Erstellen der CA werden wir nochmal nach den Angaben gefragt, die auch schon in der vars-Datei stehen. Letztenlich können wir aber alles mit <ENTER>, bzw. <y> beantworten.

Nachdem die CA angelegt wurde, kann das Server-Zertifikat erstellt werden:

./build-key-server diskette.dyn.debian-hell.org

Statt diskette.dyn.debian-hell.org muss natürlich EUER Systemname eingetragen werden, auf dem der OpenVPN-Dienst läuft. Auch hier werden wir wieder nach den Angaben gefragt, die schon in der vars-Datei festgelegt wurden, wieder <ENTER> und <y>.

Nun brauchen wir noch eine Diffie-Hellman Datei für den Schlüsselaustausch. Diese erstellen wir mit…

./build-dh

Nun haben wir vorerst alle Zeritifkate und Zertifikats-Dateien und finden diese unter /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/ wieder. Das Verzeichnis keys können wir uns auch direkt in das Stamm-Config-Verzeichnis /etc/openvpn/ kopieren:

cp -av /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/ /etc/openvpn/

Als Nächstes machen wir uns an die Konfiguration des Daemons. Dazu erstellen wir die Datei client.dialin.conf und füllen diese mit den folgenden Werten:

# An welche lokale IP soll sich der Dienst binden?
local 192.168.2.254
 
# OpenVPN soll auf Port 443 über TCP laufen
port 443
proto tcp
 
# Um externe Firewalls und Proxies auszutricksen, gaukeln wir vor ein HTTPS-Server zu sein.
tls-server
 
# Wir wollen einen IP gerouteten Tunnel
dev tun
 
# Angabe unserer Zertifikats-Dateien
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/diskette.dyn.debian-hell.org.crt
key /etc/openvpn/keys/diskette.dyn.debian-hell.org.key
 
# Liste von CN/Zertifikaten, die nicht (mehr) gültig sind
crl-verify /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/crl.pem
 
# Zusätzlich zur normalen Zertifikats-Authentifizierung soll noch Username und Passwort angegeben werden.
# Dies bewerkstelligen wir mittels eines Wrapper-Scripts. Dazu später mehr.
auth-user-pass-verify /usr/local/sbin/openvpn-auth via-file
script-security 2
 
# Diffie-Hellman Parameter Datei
dh /etc/openvpn/keys/dh2048.pem
 
# Angabe eines Verzeichnis für temporäre Dateien
tmp-dir /dev/shm/
 
# Angabe unseres OpenVPN-Netzwerks, sprich aus welchem Bereich den OpenVPN Clients IP-Adresse zugewiesen
# werden sollen. Achtung: Für jeden Client werden 4 IP-Adressen vergeben (Netzwerk-Adresse, Client-Adresse,
# Gateway-Adresse, Broadcast-Adresse), ergo großzügig planen!
server 172.16.2.224 255.255.255.240
 
# Anhand von Nutzernamen/Zertifikats CommonName können auch statische IP-Adressen zugewiesen werden.
ifconfig-pool-persist /etc/openvpn/ip_client_pool.txt
 
# Anhand des Nutzernamen/Zertifikats CommonName können Client-spezifische Routing-Einstellungen
# vorgenommen werden
client-config-dir /etc/openvpn/ccd
 
# Aller 10 Sekunden soll ein Kontroll-Ping zum Client ausgeführt werden, ob dieser noch lebt/online
# ist. Gibt es insgesamt 60 Sekunden keine Antwort, ist der Client offline
keepalive 10 60
 
# Komprimierung im Tunnel aktivieren
comp-lzo
 
# aktuell eingewählte Clients und Daemon-Meldungen sollen in entsprechende Log-Files
status /var/log/openvpn/status.log
log-append /var/log/openvpn/append.log
 
# Wieviel und mit welcher Detailtiefe soll gelogt werden?
verb 3
 
# 20 gleiche Nachrichten hintereinander werden zu einer zusammengefasst im Log
mute 20
 
# Den eingewählten Clients wird mitgeteilt, dass sich das Netzwerk //172.16.2.240/28// über das OpenVPN
# erreichbar ist.
push "route 172.16.2.240 255.255.255.240"

Wie schon in der Config kurz angeschnitten, brauchen wir noch ein Wrapper-Script für die Überprüfung des Nutzernamen und Passworts. Das Script wird angelegt und entsprechend geschrieben:

> /usr/local/sbin/openvpn-auth
chmod +x /usr/local/sbin/openvpn-auth
vim /usr/local/sbin/openvpn-auth
#!/usr/bin/perl -t -w
use strict;
use warnings;
 
# where to find the vpn users
my $vpn_user_filename = "/etc/openvpn/vpnuser.txt";
 
sub fail {
    print @_;
    exit 1;
}
 
# Get username/password from file
my $auth_filename = shift @ARGV;
 
if ( ! $auth_filename ) {
    fail( "No username/password file specified on command line\n" );
}
 
open( my $AUTHFILE, "<", $auth_filename )
    or fail( "Could not open username/password file: $auth_filename\n" );
 
my $username = <$AUTHFILE>;
my $password = <$AUTHFILE>;
 
close ( $AUTHFILE );
 
if ( !$username || !$password ) {
    fail( "Username/password not found in file: $auth_filename\n" );
}
 
chomp $username;
chomp $password;
 
open ( my $USERFILE, "<", $vpn_user_filename )
    or fail( "Could not open vpn user file: $vpn_user_filename\n" );
 
my $user_found  = 0;
my $password_ok = 0;
 
while ( my $line = <$USERFILE> ) {
    chomp $line;
 
    # skip some lines
    next if ( $line =~ m/ \A \#     /xms ); # comments
    next if ( $line =~ m/ \A \s* \z /xms ); # empty lines
 
    my ( $user, $pwd ) = split( ":", $line );
    chomp $user;
    chomp $pwd;
 
    # skip invalid lines
    next if ( !$user || !$pwd );
 
    $user_found  = ( $user eq $username );
    $password_ok = ( $pwd  eq $password );
    last if ( $user_found );
}
 
close ( $USERFILE );
 
fail( "User '$username' not found.\n"                 ) if ( ! $user_found  );
fail( "User '$username' found, but wrong password.\n" ) if ( ! $password_ok );
 
print "Ok\n";
exit 0;

Das Script bekommt 2 Umgebungsvariablen von OpenVPN übergeben, nämlich Nutzername und Passwort. Diese werden gegen die Datei /etc/openvpn/vpnuser.txt geprüft. Die Datei /etc/openvpn/vpnuser.txt legen wir gleich an und füllen Sie mit einem Nutzernamen:

> /etc/openvpn/vpnuser.txt
chmod 400 /etc/openvpn/vpnuser.txt
echo 'username:passwort' > /etc/openvpn/vpnuser.txt

Wichig ist, dass Username und Passwort mit einem ':' (Doppelpunkt) getrennt werden. Dabei ist aber noch Folgendes zu beachten:

  • pro Zeile darf nur ein Username mit Passwort stehen
  • am Ende jeder Zeile muss ein Zeilenumbruch erfolgen
  • der Username sollte mit dem im Zertifikat gesetzen CommonName übereinstimmen, dazu aber gleich mehr
  • das Passwort wird unverschlüsselt, also im Klartext, angegeben

Wie schon in der Config angegeben, wollen wir auch statische IP-Adressen im VPN für unsere Clients verwenden. Aber: Es handelt sich hier um eine Art Empfehlung. Der Client kann letztendlich die IP-Adresse verwerfen und sich eine eigene Neue setzen. Trotzdem macht diese Einstellung sind, sofern man ein trusted Network betreibt, also den Clients vertraut.

echo 'username,172.16.2.230' > /etc/openvpn/ip_client_pool.txt

Nun lassen sich noch, abhängig vom Nutzernamen, Routen und weitere Optionen setzen. Dazu muss im Pfad /etc/openvpn/ccd/ eine Datei angelegt werden, die den gleichen Namen wie der CommonName, bzw. der Username trägt. Was letztendlich alles in so eine Datei rein kann, werde ich hier nicht weiter beschreiben, dazu verweise ich auf die Dokumentation von OpenVPN.

So, der Konfigurations-Teil ist nun fertig. Nachdem OpenVPN (neu)gestartet wurde, sollte schonmal theoretisch ein Login möglich sein…

/etc/init.d/openvpn restart

Aber, es fehlt noch das Client-Zertifikat. Dazu kommen wir jetzt.

Client-Konfiguration

Die Konfigurations-Datei des Clients legen wir uns schreiben Folgendes rein:

# VPN-Server und Port, zusätzliche Angabe, dass wir uns zu einem (Fake-)HTTPS-Server verbinden
remote diskette.dyn.debian-hell.org
port 443
proto tcp-client
tls-client
 
# Wir wollen einen IP gerouteten Tunnel
dev tun
 
# PING-Interval zum VPN-Server
ping 10
 
# Komprimierung aktivieren
comp-lzo
 
# Angabe der Server CA, der Client-Zertifikats-Dateien, und dass wir nach Usernamen und Passwort
# gefragt werden sollen
ca	  ca.crt
cert      daniel.crt
key       daniel.key
auth-user-pass
 
# Einstellungen für das Log-File
verb 2
mute 10
 
# Windows-spezifische Einstellungen, damit das setzen von Routen klappt
route-method exe
route-delay 2
 
# per PUSH-Befehl vom VPN-Server gesetze Routen sollen akzeptiert werden
pull

Client-Zertifikat ausstellen

Zum Ausstellen eines Client-Zertifikats bedienen wir uns wieder der easyrsa-Scripte im Verzeichnis /usr/share/doc/openvpn/examples/easy-rsa/2.0/:

./build-key username

username sollte natürlich durch einen richtigen Usernamen ersetzt. Anschließend werde wir wieder nach den Parametern aus der vars-Datei gefragt, auch hier wieder <ENTER> und <y>…

Anschließend befinden sich im Verzeichnis keys die Dateien…

username.crt
username.csr
username.key

Diese Dateien werden zusammen mit der Datei ca.crt auf den Client kopiert. Diese werden, neben der oben genannten Client-Config, für die Einwahl benötigt.

Client-Zertifikat zurückziehen

Auch zum zurückziehen bereits ausgestellter Client-Zertifikate bedienen wir uns der easyrsa-Scripte:

./revoke-full username
Using configuration from /usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl.cnf
Revoking Certificate 05.
Data Base Updated
Using configuration from /usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl.cnf
username.crt: /C=DE/ST=Sachsen/L=Dresden/O=Debian-Hell.org Home-Office/CN=username/emailAddress=noc@debian-hell.org
error 23 at 0 depth lookup:certificate revoked

Anschließend sollte im Verzeichnis keys die Datei crl.pem einen aktuellen Zeitstempel haben. Da werden nämlich unsere ungültigen Zertifikate hinterlegt.

ACHTUNG: Das zurückziehen von Zertifikaten funkioniert natürlich nur, wenn dies auch in der OpenVPN-Config konfiguriert ist (crl-verify).

braindump/aufbau_eines_vpns_mit_openvpn.txt · Zuletzt geändert: 2017/02/16 13:57 von Daniel Graf