User Tools

Site Tools


doc:appunti:linux:sa:openvpn

OpenVPN con chiave RSA

Configurazione di openssl

La configurazione di OpenVPN in mode server (multi-client server) prevede l'uso di TLS e di una infrastruttura di chiavi e certificati (PKI), gestita tramite openssl(1).

Il comando openssl(1) legge le impostazioni predefinite da /etc/ssl/openssl.cnf. È possibile usare un file diverso passando il parametro -config oppure specificare alcuni parametri sulla riga di comando. In questi esempi si utilizza un file personalizzato /etc/openvpn/ssl/openssl.cnf. Rispetto al file di configurazione standard Debian si sono modificati i parametri:

[ CA_default ]
dir                            = /etc/openvpn/ssl # Where everything is kept
default_days                   = 1095     # how long to certify for
default_crl_days               = 1095     # how long before next CRL
default_bits                   = 2048

[ req_distinguished_name ]
countryName_default            = IT
stateOrProvinceName_default    = Italy
localityName_default           = Firenze
0.organizationName_default     = Rigacci.Org
organizationalUnitName_default = Network Services
commonName_default             = www.rigacci.org
emailAddress_default           = niccolo@rigacci.org

[ req ]
default_days                   = 1095

Configurazione del server

Elenco dei file da creare (percorso relativo a /etc/openvpn/):

  • server.rigacci.org.conf OpenVPN configuration file
  • ssl/server.rigacci.org_dh2048.pem
  • ssl/rigacci.org_cacert.pem Certificate Authority (CA) public certificate in .pem format
  • ssl/rigacci.org_crl.pem Certificate Revocation List in .pem format
  • ssl/server.rigacci.org_cert.pem server public certificate
  • ssl/private/rigacci.org_cakey.pem Certificate Authority (CA) private key (chmod 0600)
  • ssl/private/server.rigacci.org_key.pem server private key (chmod 0600)

La Certificate Signing Request (ssl/server.rigacci.org_csr.pem) dopo averla usata non serve più, basta tenere il certificato firmato.

Le caratteristiche principali di questa configurazione sono:

  • Un solo tunnel allocato sul server.
  • Un solo indirizzo IP allocato per ogni client. Se alcuni dei client sono Windows e la versione di OpenVPN è inferiore alla 2.1 purtroppo è necessario allocare una subnet /30 per ogni client (si usa la topologia net30 invece di subnet).
  • Possibilità di allocazione dinamica o statica degli indirizzi dei client.
  • Push della configurazione dal server verso i client.
  • Push di opzioni personalizzate per ciascun client.

Questo il principale file di configurazione, tra i commenti si trovano i comandi openssl(1) necessari a gestire la PKI (Public Key Infrastructure).

#---------------------------------------------------------------
# /etc/openvpn/server.rigacci.org.conf
# OpenVPN in mode server (TLS and multi-client).
#---------------------------------------------------------------
# How much and where to write some debug info.
#verb 5
#status /var/run/openvpn.server.rigacci.org.status
#status-version 2

# Use the default OpenVPN port.
port 1194

# Use TUN device to encapsulate IPv4.
dev tun194

# Empirically measure MTU on connection startup.
mtu-test

# TLS mode works by establishing control and data channels
# which  are  multiplexed over a single TCP/UDP port.
# Enable TLS and assume server role during TLS handshake.
mode server
tls-server

# At certificate creation time, we use an ssl/openssl.cnf configuration file
# with the following customization:
#   dir          = /etc/openvpn/ssl      # Where to store all the PKI files.
#   default_days = 1095                  # Default expiration time for certificates and req.
#   default_bits = 2048                  # Default key lenght.

# File containing Diffie Hellman parameters in .pem format
# Diffie Hellman parameters may be considered public.
# Generated by: openssl dhparam -out ssl/server.rigacci.org_dh2048.pem 2048
dh ssl/server.rigacci.org_dh2048.pem

# Certificate Authority (CA) file in .pem format.
# Generated by:
# mkdir ssl/private
# chmod 0700 ssl/private
# openssl req -config ssl/openssl.cnf -days 3653 -nodes -new -x509 \
#     -keyout ssl/private/rigacci.org_cakey.pem -out ssl/rigacci.org_cacert.pem
# chmod 0600 ssl/private/rigacci.org_cakey.pem
ca ssl/rigacci.org_cacert.pem

# Local peer's signed certificate in .pem format. Signed by the certificate
# authority whose certificate is in "ca" file.
# You must first create the Certificate Signing Request and then sign it:
# openssl req -config ssl/openssl.cnf -nodes -new \
#     -keyout ssl/private/server.rigacci.org_key.pem -out ssl/server.rigacci.org_csr.pem
# chmod 0600 ssl/private/server.rigacci.org_key.pem
# touch ssl/index.txt
# mkdir ssl/newcerts
# test -f ssl/serial || echo "00" > ssl/serial
# openssl ca -config ssl/openssl.cnf -in ssl/server.rigacci.org_csr.pem -cert ssl/rigacci.org_cacert.pem \
#     -keyfile ssl/private/rigacci.org_cakey.pem -out ssl/server.rigacci.org_cert.pem
# rm ssl/server.rigacci.org_csr.pem
cert ssl/server.rigacci.org_cert.pem

# Local peer's private key in .pem format, generated when you
# built your peer's Certificate Signing Request.
key ssl/private/server.rigacci.org_key.pem

# Certificate revocation list in PEM format.
# Generated by:
# test -f ssl/crlnumber || echo "01" > ssl/crlnumber
# openssl ca -config ssl/openssl.cnf -gencrl -keyfile ssl/private/rigacci.org_cakey.pem \
#     -cert ssl/rigacci.org_cacert.pem -out ssl/rigacci.org_crl.pem
#
# To revoke a certificate (then you need to regenerate the list):
# openssl ca -config ssl/openssl.cnf -keyfile ssl/private/rigacci.org_cakey.pem \
#     -cert ssl/rigacci.org_cacert.pem -revoke ssl/newcerts/03.pem
crl-verify ssl/rigacci.org_crl.pem

# Allocates one /30 subnet per client.
# This mode is compatible with Windows clients and with OpenVPN 2.0.
# The more advanced "subnet" topology requires OpenVPN 2.1.
topology net30

# Configure IP adresses for network topology:
# - Set tun adapter IP address.
# - Set a route for the clients PtP interface.
# - Push some config to the clients.
# - Use dinamically assigned IP addresses for the clients.
ifconfig 10.38.0.1 10.38.0.2
route 10.38.0.0 255.255.0.0 vpn_gateway
push "route 10.38.0.1"
push "topology net30"
ifconfig-pool 10.38.0.4 10.38.99.251
#
# To simplify the above configuration you can use the helper directive
# server 10.38.0.0 2552.255.0.0
# which is equivalent to setting all the following parameters:
# ifconfig, route, push "route", push "topology", ifconfig-pool

# Allow multiple clients with the same common name to concurrently connect.
#duplicate-cn

# Directory with per-client configuration files.
# Each file is named as the "CN" attribute of the certificate.
client-config-dir rigacciorg_server_clients

# Push some other configuration to remote clients.
push "route 192.168.200.0 255.255.255.0"

# Set "ping" and "ping-restart" options locally
# and also push them to the remote client.
keepalive 60 600

Si può fare il push verso il client di parametri specifici per il client stesso, basta creare un file con nome uguale al CN usato nel certificato e salvarlo nella directory indicata da client-config-dir. Ad esempio per assegnare un IP sempre uguale ad un client si crea il file rigacciorg_server_clients/rigacciorg_client con il seguente contenuto:

ifconfig-push 10.38.100.2 10.38.100.1

Notare che l'indirizzo è assegnato fuori dal pool definito da ifconfig-pool, inoltre gli indirizzi vanno assegnati con la topologia net30, cioè per ogni host viene allocato un blocco di 4 indirizzi: il primo è inutilizzato, il secondo è il PtP assegnato al server, il terzo è il PtP assegnato al client e il quarto è inutilizzato.

I file gestiti da openssl sono in formato PEM (X.509 Privacy Enhanced Mail), si tratta di una codifica base64 con header. Ecco alcuni comandi per vedere in plain text il contenuto dei file.

Per vedere il contenuto di una Certificate Signing Request (pubblico):

openssl req -text -noout -in rigacciorg_server.csr

Per vedere il contenuto di un Certificate e la sua fingerprint (informazioni pubbliche):

openssl x509 -text -noout -in rigacciorg_ca_cert.pem
openssl x509 -noout -fingerprint -in rigacciorg_ca.cert.pem

Per vedere il contenuto di un Certificate Revocation List (pubblico):

openssl crl -text -noout -in rigacciorg_ca_crl.pem

Visualizza il contenuto di una chiave (non molto utile, per la verità):

openssl rsa -in rigacciorg_server_key.pem -noout -text

Revoca di un certificato client (chiave)

Qualora si voglia impedire l'accesso ad un client (oppure se la sua chiave è stata compromessa), si revoca…

openssl ca -config ssl/openssl.cnf \
    -cert ssl/rigacciorg_cacert.pem -keyfile ssl/private/rigacci.org_cakey.pem \
    -revoke niccolo@rigacci.org_cert.pem

Una copia del certificato dovrebbe essere presente dal momento della sua creazione in ssl/newcerts/XX.pem.

Questa operazione non aggiorna la CRL, ma solo l'indice ssl/index.txt, bisogna rigenerare la lista con

openssl ca -config ssl/openssl.cnf \
    -cert ssl/rigacciorg_cacert.pem -keyfile ssl/private/rigacci.org_cakey.pem \
    -gencrl -out ssl/rigacci.org_crl.pem

Configurazione del client

Per ogni client si prepara un certificato e un file di configurazione. Per comodità ogni certificato viene identificato da un indirizzo email.

Questi i file necessari in /etc/openvpn/:

  • niccolo@rigacci.org.conf
  • niccolo@rigacci.org_key.pem
  • niccolo@rigacci.org_cert.pem
  • rigacciorg_ca_cert.pem

Il Certificate Signing Request (niccolo@rigacci.org_csr.pem) non è necessario, basta il certificato firmato.

I file vanno preparati sul server (dove c'è la Certification Authority), con questi comandi:

cd /etc/openvpn/ssl
openssl req -config ./openssl.cnf -nodes -new -subj "/CN=niccolo@rigacci.org" \
    -keyout "niccolo@rigacci.org_key.pem" -out "niccolo@rigacci.org_csr.pem"
chmod 0600 "niccolo@rigacci.org_key.pem"
openssl ca -config ./openssl.cnf -days 1095 -in "niccolo@rigacci.org_csr.pem" \
    -cert ssl/rigacciorg_ca_cert.pem -keyfile ssl/pki/private/rigacciorg_ca_key.pem
    -out "niccolo@rigacci.org_cert.pem"
rm "niccolo@rigacci.org_csr.pem"

Ecco infine il file di configurazione niccolo@rigacci.org.conf:

#---------------------------------------------------------------
# /etc/openvpn/niccolo@rigacci.org.conf
#---------------------------------------------------------------
# Enable TLS and assume client role during TLS handshake,
# Accept options pushed  by the server.
# This is equivalent to the tls-client and pull options.
client

# Remote server to connect to.
remote net.rigacci.org 1194
proto udp

# Use TUN device to encapsulate IPv4.
dev tun

# Certificate authority (CA) file in .pem format, copied from the CA server.
ca rigacciorg_ca_cert.pem

# Local peer's private key and local peer's signed certificate, in .pem format.
# Generated on the server and signed by the certificate authority whose certificate
# is in "ca_cert.pem" file.
key niccolo@rigacci.org_key.pem
cert niccolo@rigacci.org_cert.pem

persist-key
persist-tun
verb 3

# Some hacks required if you are doomed to use MS-Windows.
route-method exe
route-delay 2

Rinnovo del certificato del server

Quando scade il certificato del server smettono di funzionare TUTTE le VPN. Per fortuna è sufficiente rinnovare tale certificato e non è necessario distribuirlo su tutti i client. La procedura che segue genera una nuova chiave e un nuovo certificato firmato dalla stessa CA locale.

Il discorso è diverso quando scade il certificato della CA locale, in questo caso per ripristinare il funzionamento delle VPN senza distribuire il nuovo CA cert è necessario utilizzare un trucco: generare un nuovo CA cert, ma riutilizzando la vecchia chiave . La soluzione (da verificare) è descritta nel post Certification authority root certificate expiry and renewal. Altri dettagli si trovano nel post Expired CA - clients can't connect.

ATTENZIONE ai nomi dei file, che sono diversi rispetto agli esempi riportati sopra; tutto è stato eseguito nella directory /etc/openvpn/ssl/. La seguente ricetta è stata verificata su Debian 8 Jessie. YMMV!

Anzitutto si deve revocare il vecchio certificato, altrimenti al momento della firma del nuovo si ottiene l'errore:

failed to update database
TXT_DB error number 2

infatti il nuovo certificato avrà lo stesso nome del vecchio. Dopo aver revocato un certificato si deve sempre rigenerare la CRL lista dei certificati revocati. ATTENZIONE a individuare il corretto certificato! Nel nostro esempio è 00.pem, ma si deve verificare il file index.txt e i file nella directory newcerts/:

# Revoke old certificate.
openssl ca -config openssl.cnf -keyfile private/vpn.rigacci.org_cakey.pem \
    -cert vpn.rigacci.org_cacert.pem -revoke newcerts/00.pem
# Generate the new CRL.
openssl ca -config openssl.cnf -gencrl -keyfile private/vpn.rigacci.org_cakey.pem \
    -cert vpn.rigacci.org_cacert.pem -out vpn.rigacci.org_crl.pem

Alla richiesta di A challenge password e An optional company name si è lasciata una risposta vuota.

Il vecchio certificato può essere salvato o rimosso:

mv private/vpn.rigacci.org_key.pem private/vpn.rigacci.org_key.pem.expired
mv vpn.rigacci.org_cert.pem vpn.rigacci.org_cert.pem.expired

Ecco quindi la generazione del nuovo certificato con la relativa richiesta di firma CSR, seguita dalla firma da parte della CA:

openssl req -config openssl.cnf -nodes -new \
     -keyout private/vpn.rigacci.org_key.pem -out vpn.rigacci.org_csr.pem
chmod 0600 private/vpn.rigacci.org_key.pem
openssl ca -config openssl.cnf -in vpn.rigacci.org_csr.pem -cert vpn.rigacci.org_cacert.pem \
    -keyfile private/vpn.rigacci.org_cakey.pem -out vpn.rigacci.org_cert.pem
rm vpn.rigacci.org_csr.pem
doc/appunti/linux/sa/openvpn.txt · Last modified: 2020/02/24 17:59 by niccolo