Pour la faire simple, c’est globalement le bordel. On a commencé à fournir des VPNs alors que l’on avait pas encore de plan d’adressage, du coup on a des /32 hors du /27 de VPN qui se baladent. C’est pour cela que l’on a de l’iBGP vers nominoe.
Nous remarquerons que ça ne dérange pas du tout OpenVPN d’avoir des IPs en dehors de son /27.
J’ai impunément piqué l’idée d’ARN de factoriser les confs, c’est quand même vachement plus pratique quand je dois faire des modifications. Ainsi, on a trois fichier : common.ovpn qui contient la conf en commun, tcp.conf pour la partie TCP et upd.conf pour la partie UDP.
# Serveur mode server port 1194 tun-ipv6 #local 89.234.186.3 # Adresse d'écoute pour les connexions entrantes # Contournement des soucis de fragmentation mssfix 1300 # On utilise la meilleure méthode de chiffrement cipher aes-256-cbc # Certificats ca /etc/ssl/grifon/vpn.grifon.fr.CA-OPENVPN.crt cert /etc/ssl/grifon/vpn.grifon.fr.OPENVPN.crt key /etc/ssl/grifon/vpn.grifon.fr.OPENVPN.key dh dh4096.pem # Clé partagée (0 pour serveur, 1 pour client ; oui, même fichier côté client # et côté serveur) tls-auth ta.key 0 # Réseau push "dhcp-option DNS 89.234.186.4" # Serveur DNS push "dhcp-option DNS 2a00:5884::7" # Serveur DNS keepalive 10 120 # Scripts pour ajouter les bonnes routes sur judicael script-security 3 client-connect /etc/openvpn/client-connect # Utilisé pour IPv4 client-disconnect /etc/openvpn/client-disconnect # Utilisé pour IPv4 # # server implique push topology et tls-server # topology subnet server 89.234.186.64 255.255.255.224 push "explicit-exit-notify" # Pour pas que le serveur attende un timeout # Configuration IPv6 push "tun-ipv6" ifconfig-ipv6 2a00:5884:0:3::/64 2a00:5884:0:3:: # Securité user openvpn # Le serveur ne tourne pas en tant que root group openvpn persist-key persist-tun comp-lzo # On compresse client-config-dir /etc/openvpn/ccd # Chaque client a ses IP spécifiées ici # Auth auth-user-pass-verify "/etc/openvpn/auth.sh /etc/openvpn/passwd" via-env verify-client-cert none username-as-common-name ccd-exclusive # Si le client n'a pas de fichier dans /etc/openvpn/ccd, on refuse la connexion # Log verb 3 mute 20 status /etc/openvpn/openvpn-status.log # Liste des clients connectés #log-append /var/log/openvpn.log # Logs # routage up "/etc/openvpn/up.sh"
# COMMON CONFIGURATION config /etc/openvpn/common.ovpn proto tcp6-server dev tun-tcp0 daemon ovpn-server-tcp learn-address /etc/openvpn/setup-address-tcp.sh # Utilisé pour IPv6
# COMMON CONFIGURATION config /etc/openvpn/common.ovpn proto udp6 dev tun-udp0 daemon ovpn-server-udp learn-address /etc/openvpn/setup-address.sh # Utilisé pour IPv6 fragment 1300 # https://winaero.com/blog/speed-up-openvpn-and-get-faster-speed-over-its-channel/ sndbuf 0 rcvbuf 0 push "sndbuf 0" push "rcvbuf 0"
Tous les fichiers qui suivent doivent être exécutables.
Son but est de vérifier le mot de passer envoyé par le client par rapport au contenu de /etc/openvpn/passwd
.
#!/bin/sh htpasswd -bv "$1" "${username}" "${password}"
Ce fichier ajoute la route /32 pour les clients en dehors du /27 du plan d’adressage
#!/bin/sh set -e # debug #set -x #exec &> /tmp/client-connect.log [ -z "$ifconfig_pool_remote_ip" ] || sudo /bin/ip route add $ifconfig_pool_remote_ip/32 dev $dev proto static routed_IPv4_addr=$(awk '/^iroute / { print $2 }' /etc/openvpn/ccd/${username}) routed_IPv4_netm=$(awk '/^iroute / { print $3 }' /etc/openvpn/ccd/${username}) if [ -n "${routed_IPv4_addr}" ]; then if [ -n "${routed_IPv4_netm}" ]; then sudo /bin/ip route add \ ${routed_IPv4_addr}/${routed_IPv4_netm} dev ${dev} \ proto static else sudo /bin/ip route add \ ${routed_IPv4_addr}/32 dev ${dev} proto static fi fi
Comme avant sauf que l’on enlève la route (en même temps, vu le nom du fichier…)
#!/bin/sh set -e [ -z "$ifconfig_pool_remote_ip" ] || sudo /bin/ip route del $ifconfig_pool_remote_ip/32 dev $dev proto static || true
Là c’est la version du future (donc IPv6), qui fait les deux en même temps.
#!/bin/bash action="$1" addr="$2" grep -qE "^2a00:.*" <<< "$addr" if [ $? -eq 0 ] then case "$action" in add ) sudo /bin/ip route add $addr dev tun0 proto static metric 1024 ;; delete) sudo /bin/ip route del $addr dev tun0 proto static metric 1024 || true ;; esac fi
Pour que le VPN puisse être joint depuis tous les ports, nous devons les rediriger vers le 1194. En effet, OpenVPN ne sait pas écouter sur plusieurs ports, et ce serait un peu lourd d’avoir un processus par port. Nous utilisons pour cela le module NAT d’iptables.
Nous avons aussi un daemon L2TP et IPsec qui tourne, nous ne voulons pas rediriger le trafic à destination de ces ports OpenVPN, donc nous mettons juste un -j ACCEPT avant la règle de NAT. Absolument tous les ports TCP sont redirigés, il n’est donc pas possible de se connecter en SSH au serveur VPN en IPv4.
iptables -t nat -A PREROUTING -d 89.234.186.190/32 -p udp -m udp --dport 1:65535 -j DNAT --to-destination 89.234.186.190:1194 iptables -t nat -A PREROUTING -d 89.234.186.190/32 -p tcp -m tcp --dport 1:65535 -j DNAT --to-destination 89.234.186.190:1194 iptables -A INPUT -s 89.234.186.0/24 -d 172.16.0.0/12 -j DROP iptables -A FORWARD ! -s 172.16.0.0/12 -d 172.16.0.0/12 iptables -A OUTPUT -s 172.16.0.0/12 -d 89.234.186.0/24 -j DROP
ip6tables -A PREROUTING -d 2a00:5884:0:2:ffff:ffff:ffff:ffff/128 -p tcp -m tcp --dport 1:65535 -j DNAT --to-destination [2a00:5884:0:2:ffff:ffff:ffff:ffff]:1194 ip6tables -A PREROUTING -d 2a00:5884:0:2:ffff:ffff:ffff:ffff/128 -p udp -m udp --dport 1:65535 -j DNAT --to-destination [2a00:5884:0:2:ffff:ffff:ffff:ffff]:1194
Par défaut, openvpn écrit ses logs dans /var/log/daemons.log
. Nous voulons un fichier séparé car ils sont très vite très gros avec tous les bots qui tentent de se connecter au VPN en TCP en croyant tomber sur un serveur mail/web/whateverd. J’ai donc écrit un fichier de conf rsyslog :
if $programname startswith 'ovpn-server-' then { -/var/log/openvpn.log }
Si un client veut un mot de passe particulier, il peut donner la sortie de htpasswd -n $username
Je ne copie pas ici la clé partagée (ta.key) parce que ça n’aurait aucun sens. Elle est envoyée à l’adhérent lors de la création de son compte.
# OpenVPN chez Grifon # Informations de connexion client dev tun proto udp #proto tcp-client port 1194 remote vpn.grifon.fr 1194 remote-random resolv-retry infinite remote-cert-tls server route-delay 2 nobind persist-key # Configuration pour contourner les soucis de fragmentation fragment 1300 mssfix 1300 # Chiffrement le plus élevé cipher aes-256-cbc # Clé partagée (à ne pas distribuer) tls-auth ta.key 1 comp-lzo redirect-gateway def1 bypass-dhcp # À commenter pour ne pas utiliser le VPN comme connexion IPv4 par défaut route-ipv6 2000::/3 # À commenter pour ne pas utiliser le VPN comme connexion IPv6 par défaut # Auth auth-user-pass # CA <ca> -----BEGIN CERTIFICATE----- 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 2kSONme/cdZptUNl2KZzs+xYBeyUPSRE -----END CERTIFICATE----- </ca>
OpenVPN ajoute les routes IPv4 0.0.0.0/1 via 89.234.186.65 dev tun0
et 128.0.0.0/1 via 89.234.186.65 dev tun0
, sauf que dans le cas du /32, 89.234.186.65 n’est pas directement joignable. Il faut donc ruser avec un up.sh :
#!/bin/sh dev=$1 ip route add 89.234.186.65/32 dev $dev
alarig@judicael:~$ add-ovpn -h Usage: -h, --help Affiche ce message d’aide -u, --user Identifiant de connexion au VPN -i, --id Numéro servant à la génération des IPs -m, --email Adresse mail à qui envoyer les informations de connexion
Exemple :
ovpn-add -u toto -m toto@super.bzh
Ce qui configurera les adresses ip:
Si vous êtes curieux, voici le script :
#!/bin/sh usage() { printf "Usage:\n" printf "\t-h, --help Affiche ce message d’aide\n" printf "\t-u, --user Identifiant de connexion au VPN\n" printf "\t-i, --id Numéro servant à la génération des IPs\n" printf "\t-m, --email Adresse mail à qui envoyer les informations de connexion\n" } OPTS=$(getopt -o u:,m:,h -l user:,email:,help -- "$@") if [ $? != 0 ]; then exit 1 fi if [ $1 ]; then if [ $1 = '-h' ] || [ $1 = '--help' ]; then usage exit 0 elif [ $# -lt 4 ]; then echo "Paramètre manquant" usage exit 1 fi else echo "Paramètre manquant" usage exit 1 fi eval set -- "$OPTS" while :; do case "$1" in -h | --help) usage; exit 0;; -u | --user) user="$2"; shift 2;; -m | --email) EMAIL="$2"; shift 2;; --) shift; break;; esac done mailregex=$(echo $EMAIL | egrep '[^.]+@[^.]+\.[^.]+') if [ ${#mailregex} != ${#EMAIL} ]; then echo "Adresse mail invalide" exit 1 fi #ipv6="2a00:5884:$((8300+$IPid))" #ipv4="89.234.186.$IPid" # API USERAPI='user' PASSWORD='password' SUBNETID_VPNIPv4='76' SUBNETID_VPNIPv6='36' URLAPI="https://ipam.grifon.fr/api/${USERAPI}/" # Curl CURL="$(which curl) -s -k -X" HEADERHTTP='Content-type: application/x-www-form-urlencoded' # Get Token APITOKEN=$(${CURL} POST --user ${USERAPI}:${PASSWORD} --header "${HEADERHTTP}" \ ${URLAPI}/user/ | jq '.data.token' | sed 's/\"//g') #echo $APITOKEN # Get last IP # IPv4 LAST_VPN_V4=$(${CURL} POST --header "token: ${APITOKEN}" \ --header "${HEADERHTTP}" \ ${URLAPI}/addresses/first_free/$SUBNETID_VPNIPv4/ \ --data "description=VPN de $FIRSTNAME ${LASTNAME}" \ | jq .data | sed 's/\"//g') echo $LAST_VPN_V4 # IPv6 LAST_VPN_V6=$(${CURL} POST --header "token: ${APITOKEN}" \ --header "${HEADERHTTP}" \ ${URLAPI}/subnets/$SUBNETID_VPNIPv6/first_subnet/48 \ --data "description=VPN de $FIRSTNAME $LASTNAME" \ --data 'isFull=1' \ | sed 's/\\//' | jq .data | sed 's/\"//g') echo $LAST_VPN_V6 FIRST_IPv6="${LAST_VPN_V6%/48}1" password="$(head -c 12 /dev/urandom | base64)" echo "1 - Génération du mot de passe" >&2 htpasswd -nb $user $password | grep -v "^$" >> /etc/openvpn/passwd echo "2 - Génération de la configuration" >&2 echo "# IPv4 ifconfig-push $LAST_VPN_V4 255.255.255.224 # IPv6 ifconfig-ipv6-push ${FIRST_IPv6}/112 iroute-ipv6 ${LAST_VPN_V6} route-ipv6 $LAST_VPN_V6 $FIRST_IPv6" > /etc/openvpn/ccd/$user echo "3 - Envoi du mail" >&2 SUBJECT=$(perl -wse "use utf8; use Encode qw(encode); print encode(\"MIME-Q\",\ \"Votre VPN vient d’être créé\");") echo "From: Adminsys grifon <adminsys@grifon.fr> To: $EMAIL Content-Type: text/plain; charset=UTF-8 Subject: $SUBJECT Bonjour, Votre VPN vient d’être créé. Vous avez l’IPv4 $LAST_VPN_V4 et le subnet IPv6 $LAST_VPN_V6. Votre identifiant est $user et votre mot de passe est $password Si vous souhaitez utiliser un mot de passe que nous ne connaissons pas, vous pouvez nous envoyer la sortie de 'htpasswd -n $user'. Si vous voulez un reverse DNS sur votre VPN, merci d’envoyer un mail à adminsys@grifon.fr contenant le serveur qui fera autorité sur vos zones DNS. Vous trouverez ci-dessous un exemple de configuration côté client ainsi que la clé pré-partagée ##### DÉBUT DU FICHIER DE CONFIGURATION ##### $(cat /etc/openvpn/client.conf.template) ##### FIN DU FICHIER DE CONFIGURATION ##### ##### DÉBUT DE LA CLÉ PRÉ-PARTAGÉE ##### $(cat /etc/openvpn/ta.key) ##### FIN DE LA CLÉ-PARTAGÉE ##### Cette clé partagée est là pour éviter les attaques par force brute, merci de ne pas la diffuser. Cordialement, -- Les adminsys de grifon" | /usr/sbin/sendmail -f adminsys@grifon.fr -t SUBJECT=$(perl -wse "use utf8; use Encode qw(encode); print encode(\"MIME-Q\",\ \"Création du VPN de $user\");") echo "From: Adminsys grifon <adminsys@grifon.fr> To: adminsys@grifon.fr Content-Type: text/plain; charset=UTF-8 Subject: $SUBJECT IPv4 : $LAST_VPN_V4 IPv6 : $LAST_VPN_V6 " | /usr/sbin/sendmail -f adminsys@grifon.fr -t