OpenVPN

Openvpn è disponibile per praticamente tutti i sistemi operativi. Linux, Windows, BSD, Macos, ios, android. Qui elenco una serie di configurazoni "di base" per usare Openvpn in diverse situazioni. Non sono tutte configurazioni "pronte" e questa pagina è decisamente disordinata, in quanto le possibili varianti sono davvero tante.

Fra l'altro openvpn ha avuto una certa evoluzione degli ultimi anni e sono cambiate diverse cose. Alcune opzioni come la compressione sono state deprecate in maniera un pochino troppo "hard", rompendo le configurazioni pre-esistenti. Lo stesso vale per certi algoritmi crittografici. Per rendere le cose più semplici, il client per Macos e quello per ios hanno un loro concetto personale, diverso da tutti gli altri, di regole per la gestione del traffico nel tunnel.

Openvpn nelle versioni 2.5 e successive sta cambiando alcuni comportamenti, algoritmi crittografici, assegnazione degli indirizzi ip. Questo significa che diverse cose nelle config qua indicate valgono solo per versioni recenti di openvpn. Per le versioni vecchie di openvpn sarà possibile consultare le vecchie versioni di questa pagina.


Questa e` la configurazione piu` semplice del mondo, non la piu` sicura. Tuttavia è comoda da realizzare, e non è meno sicura del 99% delle connessioni ipsec che vedo in giro dai clienti con i loro firewall commerciali da 10.000 euro, una chiave preshared e algoritmi obsoleti. Questa configurazione crea un tunnel, non un bridge. In altri termini fa routing a layer 3 e non bridging a layer 2.

Se ci sono dei nat in mezzo, e il link non resta su quando non c'e` traffico, si possono aggiungere nei file di configurazione di tutti e due gli endpoint un paio di righe per il keepalive.

Per una vpn fra due endpoint (non in stile client/server) con ip e dns dinamico, si puo` cercare di ovviare ai problemi di cambio di indirizzo ip di uno dei due endpoint (anche di tutti e due, nel caso) cosi`:

In questo modo se uno dei due endpoint cambia indirizzo, dopo 300 secondi di disconnessione (causata dal cambio di indirizzo) openvpn riavvia l'handshake provvedendo anche a ri-risolvere dal dns l'ip del remoto (resolv-retry).


Configurazione per connettere diversi dispositivi portatili a un concentratore Linux con chiavi asimmetriche

Questa dovrebbe essere la configurazione piu` sicura possibile per l'uso con tanti portatili che si connettono individualmente alla rete. Utilizzo certificati e chiavi per l'autenticazione e un pool di indirizzi dinamico. Questa configurazione, cosi` com'e` fatta, accetta fino a 64 client contemporaneamente in quanto usa 4 indirizzi ip (di una subnet privata da 256 indirizzi) per ogni pc linkato. Le chiavi identificano il client, il che significa che è necessario creare una chiave diversa per ogni client, e che se due client che usano la stessa chiave si connettono nello stesso momento, le loro connessioni continueranno a flappare (andare e venire) in quanto si "ammazzano" a vicenda l'una con l'altra. L'uso di una stessa chiave su piu` client è consentito, ma solo se sono connessi uno alla volta. Peraltro siccome la chiave identifica l'utente, non è una buona idea farlo.

Questa configurazione crea un tunnel con routing IP fra subnet diverse (una per la LAN, una dedicata ai clienti in VPN) e non un bridge ethernet.

Per generare i certificati per l'autenticazione uso Easy-RSA, ma potrei usare qualsiasi sistema che mi permetta di mettere in piedi una CA privata.

Impostazione server Linux

Configurazione per i client Windows

La configurazione per i client windows e linux e` praticamente identica. Qui descrivo quella per windows, ma per Linux basta prendere i files di configurazione e metterli in /etc/openvpn (in linux il file di confiugurazione non ha estensione .ovpn ma .conf).


Configurazione "monolitica" con i certificati entrocontenuti

Volendo, è possibile creare un unico file di configurazione, che contiene anche i vari certificati, chiavi, e files "accessori". Questo file può essere usato da tutti i client a me noti ad oggi (windows, android, ios, linux) ed è più comodo da gestire rispetto al gruppo di files che abbiamo visto in precedenza.

Per farlo, in pratica si copia e incolla il contenuto dei vari files di certificato (ca.crt, client.crt, client.key, tls-auth.key) dentro al file di configurazione, all'interno dei vari blocchi <xxx> </xxx>. E` sufficiente seguire lo schema qui sotto. Notare il comando key-direction 1 che sostituisce il parametro 1 della voce tls-auth tls-auth.key 1 dell'esempio precedente.

In fondo alla pagina c'è uno script per convertire configurazioni standard in monolitiche (lo script gira su linux, ma ovviamente genera config per qualsiasi client)

Tutte le voci di configurazione che non fanno riferimento a dei files vanno lasciate esattamente come prima.

Nota bene: se la chiave e` crittata, anziche` la voce -----BEGIN RSA PRIVATE KEY----- e relativo end, occorre usare la voce -----BEGIN ENCRYPTED PRIVATE KEY----- e relativo end.

# qui vanno tutte le voci di config 
# che non fanno riferimento a dei files

key-direction 1
<ca>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
</key>
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
...
-----END OpenVPN Static key V1-----
</tls-auth>

Autenticazione con username e password

Openvpn prevede una autenticazione mista (certificati + username e password). La ritengo mediamente inutile, in quanto un certificato (dotato di una sua password) è altrettanto sicuro. In ogni caso gli appunti che avevo online (se andate a vedere le vecchie versioni di questa pagina li trovate) credo che non siano più funzionanti, troppo vecchi. Dovrei rifarli.


Configurazione LAN to LAN fra due Linux, usando le chiavi asimmetriche

Per la gestione delle chiavi, riferirsi alla sezione precedente, perche` e` identica.

Per la configurazione dei due endpoint, queste sono due configurazioni di esempio. Uno dei due endpoint sara` sempre un "server" e l'altro un "client" per quanto riguarda l'autenticazione, ma non e` importante quale dei due lo sia.

Configurazione "server". In questa configurazione non sono compresi i comandi per il keepalive che invece ha senso includere. Vedere prima per informazioni.

# per usare un device tun dinamico, usa
# "dev tun". qui ne uso uno statico.
dev tun1

# Indirizzo IP pubblico del remoto
remote xx.xx.xx.xx

# Interfaccia locale a cui mi bindo (pubblica)
local xx.xx.xx.xx

# Definizione indirizzi IP privati del tunnel.
# Questi saranno dati alle interfaccie "interne" (tunX) dei due endpoint.
# ifconfig <locale> <remoto>
ifconfig 10.0.0.254 172.16.0.253

# Definisco uno o piu` routing verso la lan remota (una o piu` righe)
# Formato: route  <netbase> <netmask>
route 172.16.0.0 255.255.255.0

# questa parta e` il server TLS
tls-server

# il file con dentro il numero primo per l'algoritmo Diffie Helman
# (serve solo per il server tls).
dh dh2048.pem

# il file con la chiave pubblica
# della CA che ha firmato i certificati per tutti gli endpoint.
ca ca.crt

# il file con la chiave pubblica del mio endpoint
cert server.crt

# il file con la chiave privata del mio endpoint
key server.key

# il file con la shared key per l'autenticazione dei pacchetti
# di handshake
#   The tls-auth directive adds an additional HMAC signature to
#   all SSL/TLS handshake packets for integrity verification.
#   Any UDP packet not bearing the correct HMAC signature can
#   be dropped without further processing
tls-auth tls-auth.key 0

# la porta che uso per i dati crittati verso/da il remoto.
# se uso "port" intendo la stessa per tutti e due,
# altrimenti uso "lport" e "rport" per locale e remoto.
# ogni tunnel deve avere una porta diversa.
port 9001

# dopo aver avviato il tunnel, posso usare questi uid e gid
# per non restare root, oppure anche no. A scelta
user nobody
group nogroup

# in caso di reload, tieni in memoria i dati che non potresti piu` rileggere a causa del privilegio insufficiente
persist-key
persist-tun

# log level (da 0 per il minimo a 9 per il massimo)
verb 3

Configurazione lato client. Fondamentalmente uguale al server se si escludono sette piccoli particolari. Anche qui vale il discorso di includere le funzioni di keepalive.

# per usare un device tun dinamico, usa
# "dev tun". qui ne uso uno statico.
dev tun1

# Indirizzo IP pubblico del remoto
remote xx.xx.xx.xx

# Interfaccia locale a cui mi bindo (pubblica)
local xx.xx.xx.xx

# Definizione indirizzi IP privati del tunnel.
# Questi saranno dati alle interfaccie "interne" (tunX) dei due endpoint.
# ifconfig <locale> <remoto>
ifconfig 172.16.0.253 10.0.0.254

# Definisco uno o piu` routing verso la lan remota (una o piu` righe)
# Formato: route  <netbase> <netmask>
route 10.0.0.0 255.255.255.0

# questa parta e` il client TLS
tls-client

# il file con la chiave pubblica
# della CA che ha firmato i certificati per tutti gli endpoint.
ca ca.crt

# il file con la chiave pubblica del mio endpoint
cert client.crt

# il file con la chiave privata del mio endpoint
key client.key

# il file con la shared key per l'autenticazione dei pacchetti
# di handshake
#   The tls-auth directive adds an additional HMAC signature to
#   all SSL/TLS handshake packets for integrity verification.
#   Any UDP packet not bearing the correct HMAC signature can
#   be dropped without further processing
tls-auth tls-auth.key 1

# la porta che uso per i dati crittati verso/da il remoto.
# se uso "port" intendo la stessa per tutti e due,
# altrimenti uso "lport" e "rport" per locale e remoto.
# ogni tunnel deve avere una porta diversa.
port 9001

# dopo aver avviato il tunnel, posso usare questi uid e gid
# per non restare root, oppure anche no. A scelta
user nobody
group nogroup

# in caso di reload, tieni in memoria i dati che non potresti piu` rileggere a causa del privilegio insufficiente
persist-key
persist-tun

# log level (da 0 per il minimo a 9 per il massimo)
verb 3


Configurazione con un server e tanti client ognuno dei quali ha una LAN dietro

Questa e` una configurazione che ho fatto per un cliente, ma vale la pena di conservarla qui. In questa configurazione c'e` un server centrale al quale si connettono tanti client (tutti linux) ognuno dei quali client e` un firewall che ha sotto di se` una rete locale. Le macchina delle varie reti dei vari client vedono quella dietro al server, e viceversa. Volendo e` possibile far vedere anche le reti client l'una con l'altra.

Questa configurazione usa tutta la subnet 10.64.0.0/16, dividendola cosi`: 10.64.0.0/24 viene usata per le interfacce "tun" di tutti i partecipanti (server e clients della vpn), e poi le reti 10.64.x.0/24 vengono usate per le LAN dietro ogni rispettivo client della VPN, assegnandole arbitrariamente con X che va da 1 a 255 alle varie reti.

Il limite di questa configurazione dovrebbe essere di 248 client con le relative reti, limite dato da come openvpn usa gli indirizzi della 10.64.0.0/24 per i vari client (10.64.0.1 va al server, e dal 4 al 254 vanno ai client).

Il sistema generale e` quello della rete per portatili con un concentratore descritto prima, con alcune modifiche. Specificamente, faccio uso di una CCD (client config directory) per assegnare a mia discrezione le varie subnet alle LAN dei client, basandomi sul common name per distinguerli l'uno dall'altro. Inoltre, uso la direttiva "ifconfig-pool-linear" (che dalla openvpn 2.10 cambia nome) sul server per assegnare un solo IP ad ogni client remoto anziche` una rete /30 dal pool 10.64.0.0/24. Questo mi permette di gestire 248 reti remote anziche` 32, pero` mi limita a non usare client (intesi come client della vpn, quindi i firewall remoti) con windows. Ovviamente i client veri e propri nelle varie LAN remote possono benissimo essere Windows. Usando openvpn 2.10 probabilmente potrei fare tutto questo anche con windows sui firewall, ma perche` mai provarci?

Configurazione lato server centrale:

# interfaccia pubblica, porta e protocollo
local 62.94.137.138
port 9000
proto udp

# device usato dalla vpn
dev tun0

# io sono il server TLS (sempre vero per una conf a un server e molti client)
tls-server

# il file con dentro il numero primo per l'algoritmo Diffie Helman
# (serve solo per il server tls).
dh dh2048.pem

# il file con la chiave pubblica
# della CA che ha firmato i certificati per tutti gli endpoint.
ca ca.crt

# il file con la chiave pubblica del mio endpoint (il server)
cert server-impianti-remoti.crt

# il file con la chiave privata del mio endpoint (il server)
key server-impianti-remoti.key

# il file con la shared key per l'autenticazione dei pacchetti
# di handshake
#   The tls-auth directive adds an additional HMAC signature to
#   all SSL/TLS handshake packets for integrity verification.
#   Any UDP packet not bearing the correct HMAC signature can
#   be dropped without further processing
tls-auth tls-auth.key 0

# indirizzi ip delle interfacce tun dei firewll
# (questo e` il classico setup da "road warrior" pero` con un solo ip per client)
server 10.64.0.0 255.255.255.0
topology p2p

# route dal kernel (locale, del server) a openvpn: tutte le 10.64.x.x ci vanno dentro
# quindi anziche` indicarle una per una, le indico tutte assieme con una /16
# i singoli firewall remoti avranno una loro configurazione "speciale" dentro alla
# directory "ccd", nel file chiamato con il loro common name, che indica quale rete
# routare a quale firewall remoto.
route 10.64.0.0 255.255.0.0

# client config dir
client-config-dir ccd

# configurazioni di routing da insegnare ai client che si collegano.
# non voglio che i client si vedano fra loro, quindi non includo
# nulla a riguardo.
# qui vanno indicate le reti LAN dietro al firewall "centrale"
push "route 10.0.0.0 255.255.0.0"
push "route 192.168.2.0 255.255.255.0"


# keepalive e timeout: ping ogni 60 secondi e timeout di 240 secondi.
keepalive 60 240

# downgrade dei privilegi utente dopo l'avvio:
user nobody
group nogroup

# in caso di reload, tieni in memoria i dati che non potresti piu` rileggere a causa del privilegio insufficiente
persist-key
persist-tun

# file che indica lo stato delle connessioni, ad uso di chi lo vuole leggere
status impianti-remoti/server-status.log


# verboso
verb 3
(END)

Configurazione lato client (firewall remoto):

client
dev tun
proto udp
nobind
float
remote <firewall sede centrale> 9000
# file con le chiavi che abbiamo copiato prima dalla directory di easy-rsa:
ca ca.crt
cert client1.crt
key client1.key

# il certificato del server deve essere di tipo "server"
# questo evita che chi possiede un certificato client possa spacciarsi per server
remote-cert-tls server
tls-auth tls-auth.key 1
#loglevel 3
verb 3

Esempio del file che va dentro alla client config directory (ccd) per un client. questo file deve avere come nome il common name del client stesso (ad esempio, client1)

# indico al server openvpn quale subnet remota (10.64.x.0/24) va a questo client:
# In questo caso la 10.64.1.0/24. 
# Ovviamente sul firewall remoto dovro` usare questa subnet per la LAN.

iroute 10.64.1.0 255.255.255.0


Problemi di MTU

Se mandando pacchetti grandi la VPN sembra morire, probabilmente avete problemi di MTU sul percorso. Potete mettere una pezza inserendo nella configurazione (del server o del client, basta uno solo dei due) la riga

mssfix 1450

oppure potete provare anche valori diversi.

Applicando (lato server) a un link fra due connessioni FTTH e VDSL, che andando in pppoe hanno MTU di 1492, un mssfix di 1450 la risultante velocità di un rsync (con forte traffico dal client al server) dentro la VPN è passata da circa 8 Mbit a 49 Mbit fissi. Considerando che il link della VDSL è da 50 Mbit e quello della FTTH da 100, direi che abbia fatto una differenza abissale.

La cosa buffa e` che leggendo il manuale di openvpn intuisco che 1450 dovrebbe essere il valore di default, ma ho verificato che impostandolo a 1450 si risolvono problemi, il che mi fa pensare che forse il valore di default era diverso da 1450 in alcune versioni piu` vecchie di openvpn. In ogni caso il trucco e` provare ad abbassarlo e vedere se si mette a funzionare correttamente.

Sempre stando al manuale, con 1450 come valore del parametro mssfix, il pacchetto udp risultante (fuori dalla vpn) dovrebbe poter passare su un path MTU di 1473 bytes, quindi dovrebbe stare dentro a qualsiasi connessione "normale", comprese quelle in pppoe che hanno MTU di 1492.

Un'altra soluzione potrebbe essere usare "fragment" per forzare la frammentazione DENTRO la VPN, in modo trasparente per i client. Questo pero` aumenta di 4 bytes la dimensione di ogni pacchetto.

fragment 1300
mssfix

Test del MTU

lanciando uno dei due lati della vpn (il client, tipicamente) con il parametro "--mtu-test", si fa un test dell' MTU sul link. Un esempio di esecuzione potrebbe essere questo:

sudo openvpn --mtu-test --config il_tuo_file_di_config.ovpn 

Il risultato mostrera` la dimensione massima dei pacchetti che openvpn e` riuscito a fare transitare nei due versi. Attenzione però: questo risultato comprende una eventuale frammentazione e ricostruzione ad opera dei vari apparati di rete lungo il tragitto. Se si vuole verificare l' MTU senza alcuna frammentazione, occorre eseguire il test cosi`:

sudo openvpn --mtu-disc yes --mtu-test --config il_tuo_file_di_config.ovpn --proto udp4

In questo modo si setta il flag DF nei pacchetti usati nel test, e si otterra` tipicamente un valore piu` basso come risultato. Se si tiene conto di questo valore nell'impostare mssfix e/o fragment dentro la vpn, si dovrebbe ottenere una condizione nella quale i pacchetti non vengono mai frammentati e quindi non di dovrebbero avere problemi di latenza, di ordine di arrivo non congruente, di firewall che bloccano i frammenti perche` sono stronzi, ecc.


Come revocare un certificato

Se dovete revocare uno o piu` certificati, occorre:

Va ricordato che qualora si revochino altri certificati in futuro, occorre ricopiare il file crl.pem dalla directory keys della CA alla directory dove lo cerca openvpn, e poi va riavviato il processo di openvpn.

Usare il CCD per dare ip statici

Questa configurazione e` relativa alla "topolgy net30" e non è più valida con topologia "subnet" con le versioni di openvpn recenti. In questa nuova topologia si da` un solo ip per client in una classe /24.

Questo e` l'elenco dei gruppi di ip validi nel comando ifconfig-push dentro al file CCD, considerando la classica allocazione di ip in subent di 4, richiesta dai client windows:

[  1,  2] [  5,  6] [  9, 10] [ 13, 14] [ 17, 18]
[ 21, 22] [ 25, 26] [ 29, 30] [ 33, 34] [ 37, 38]
[ 41, 42] [ 45, 46] [ 49, 50] [ 53, 54] [ 57, 58]
[ 61, 62] [ 65, 66] [ 69, 70] [ 73, 74] [ 77, 78]
[ 81, 82] [ 85, 86] [ 89, 90] [ 93, 94] [ 97, 98]
[101,102] [105,106] [109,110] [113,114] [117,118]
[121,122] [125,126] [129,130] [133,134] [137,138]
[141,142] [145,146] [149,150] [153,154] [157,158]
[161,162] [165,166] [169,170] [173,174] [177,178]
[181,182] [185,186] [189,190] [193,194] [197,198]
[201,202] [205,206] [209,210] [213,214] [217,218]
[221,222] [225,226] [229,230] [233,234] [237,238]
[241,242] [245,246] [249,250] [253,254]

Il comando da usare sara` quindi una cosa tipo:

ifconfig-push 10.127.0.253 10.127.0.254

Il primo ip verra` dato al client e il secondo al server.


Integrazione con Dnsmasq per risolvere i nomi dei client in vpn

Vedasi la pagina di Dnsmasq: LinuxDebian/DnsMasq


Problemi con il client iOS (iphone/ipad) e MacOS

Il client openvpn di iOS è ovviamente stronzo, come quasi ogni cosa iQualcosa. Se gli indichi un DNS e un DOMAIN con le "dhcp-option", lui decide che chiama il tuo dns solo per il dominio indicato nella opzione DOMAIN, e gli altri li chiede su internet. Il risultato è ovviamente un casino, perché tu ti aspetti che il client usi il DNS che gli hai passato nella dhcp-option, e lui invece lo usa solo per il dominio che gli hai passato. È possibile (e necessario) quindi passargli più righe di "DOMAIN", andando a coprire tutti i dominio che si vuole vengano risolti dal DNS interno della VPN e non da quello esterno.

Tunnelblick, il client per MAcOS, non è da meno, nel senso che imposta dei parametri di connessione (mtu, algoritmi di crittografia, ecc) come gli pare, con il risultato che i suoi paramentri vanno tipicamente in conflitto con quelli che imposti tu nel server. Puoi vedere questi conflitti nel log del client.

22 ottobre 2018: L'uso della compressione si è rivelato insicuro, e alcuni client (ios) hanno disattivato la compressione senza dire nulla all'utente, a partire dalla versione 3.0.2. Se la vostra VPN usava la compressione e ora non funziona più, o la togliete anche dal server, o la riattivate a mano nei client. In ogni caso a questo punto è opportuno non usare più la compressione nelle nuove installazioni.

Openvpn nuovo con certificati vecchi

Se si hanno ancora certificati che usavano l' MD5 e non l' SHA256, occorre inserire questa riga nella configurazione:

tls-cipher "DEFAULT:@SECLEVEL=0"


Script per generare configurazioni monolitiche

Se servisse generare delle configurazioni con i certificati compresi dentro al file di config, c'e` questo semplice script che permette di farlo. Prende in input il nome di un file di configurazione, e si aspetta di trovare nello stesso percorso i files dei certificati cosi` come richiamati dentro al file di configurazione, e genera un nuovo file di configurazione che contiene i certificati al loro interno. unifier.sh


Revoca delle chiavi e CRL

Se si usa una CRL per revocare chiavi, occorre ricordare una cosa molto importante: Openvpn legge la CRL all'avvio, ma se la CRL cambia, tenta di rileggerla in tempo reale ogni volta che riceve una connessione, il che e` giustissimo, ma fate attenzione: Se avete impostato openvpn per droppare i privilegi e girare come "nobody", a questo punto e` facile che non riesca piu` a leggere la CRL, col risultato che non accettera` piu` nessuna connessione. Occorre quindi riavviare openvpn per riuscire a leggere la CRL, oppure, più saggiamente, assicurari che l'utente "nobody" possa leggere il file della CRL.


Note