OpenVPN, combien dans ce mot. Un serveur VPN open source gratuit, multiplateforme et configurable de manière flexible, qui est en fait la norme de facto pour organiser l'accès aux réseaux d'entreprise internes. La plupart des administrateurs l'utilisent avec des paramètres par défaut ou avec des configurations typiques qui sont largement décrites dans différents HOW-TO. Mais OpenVPN est-il aussi simple qu'il y paraît à première vue? Dans cet article, nous considérerons les mécanismes internes d'OpenVPN, cachés aux yeux, qui changent radicalement l'idée de ses capacités.
Le serveur OpenVPN est distribué sous forme de code source ou de packages compilés prêts à installer pour différents systèmes d'exploitation. OpenSSL est utilisé comme une bibliothèque fournissant le cryptage.
La plupart des configurations de connexion des clients au serveur, ainsi qu'entre les serveurs, impliquent l'utilisation d'un tas de clés privées ou privées / publiques pour assurer la sécurité du trafic interne. Pour les réseaux d'entreprise en mode MultiPoint-To-SinglePoint, une autorité de certification PKI est généralement utilisée, ce qui est facile à construire en utilisant easy-rsa ou XCA . Pour la communication inter-serveur point à point, une configuration à clé partagée est principalement utilisée. Rappelez-vous les mécanismes et capacités de base bien connus.
Mécanismes et capacités clés
Authentification par certificat
Une énorme quantité de documentation a été écrite à ce sujet. Le point est simple. Une autorité de certification est en cours de création qui émet des certificats utilisateur. À l'aide d'une autorité de certification, un contrôle est fourni pour connecter les utilisateurs au serveur OpenVPN. Lorsque le certificat expire ou est révoqué, l'accès utilisateur est bloqué. Les clés privées avec un mot de passe défini dessus, émises conjointement avec le certificat, offrent une sécurité contre les connexions non autorisées aux ressources internes.
Clés point à point privées
Du point de vue de la connexion d'un seul utilisateur / serveur aux ressources de l'entreprise, un schéma avec des clés privées est utilisé. Une clé est générée sur l'un des hôtes, qui est partagée entre le serveur et le client.
Dans tous les cas de connexion pour la sécurité de la "prise de contact" entre le client et le serveur, le protocole Diffie-Hellmann est utilisé.
Authentification des utilisateurs externes
Pour simplifier le contrôle des connexions utilisateur, au lieu d'un schéma avec sa propre PKI, vous pouvez utiliser un schéma avec authentification externe des utilisateurs par login / mot de passe . Ce schéma est pratique pour authentifier les utilisateurs par, par exemple, un identifiant / mot de passe de domaine. Pour se connecter au serveur, le certificat de serveur et la clé de signature de paquet HARDENING OPENVPN SECURITY sont ajoutés au fichier de configuration client.
exemple de configuration client
dev tun proto udp # IP OpenVPN remote 172.16.111.166 # Port port 1200 client resolv-retry infinite tls-client key-direction 1 auth SHA1 cipher BF-CBC #comp-lzo persist-key persist-tun # auth-user-pass c:/temp/pass.txt # # just create a file with name pass.txt # and put to it two lines # ------------- #username #password # ------------- #auth-user-pass verb 3 <ca> -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIJAOt3kFH7PxA0MA0GCSqGSIb3DQEBCwUAMIGjMQswCQYD .... -----END CERTIFICATE----- </ca> <tls-auth> -----BEGIN OpenVPN Static key V1----- 83ddd29fa82212f3059d85a41490134c .... a4f2c7df3a22364a49093bca102dedeb -----END OpenVPN Static key V1----- </tls-auth>
Une partie de la configuration du serveur pour l'authentification du client via un fichier
Utilisation de méthodes d'authentification alternatives
verify-client-cert none #client-cert-not-required username-as-common-name tls-server tls-auth /usr/local/etc/openvpn/ssl/tlsauth.key key-direction 0 tls-timeout 120 auth SHA1 cipher BF-CBC auth-user-pass-verify /usr/local/etc/openvpn/auth/auth-static-file.pl via-file
Ce schéma est pratique, mais très dangereux.
PAM
Pour augmenter la sécurité, vous pouvez utiliser des plug-ins qui fournissent une vérification de connexion / mot de passe dans les systèmes externes. La méthode la plus courante est le système PAM (Pluggable Authentication Modules).
Ajoutez la ligne au fichier de configuration OpenVPN
plugin /usr/share/openvpn/plugin/lib/openvpn-auth-pam.so login
Acheminement
Parce que la tâche principale du serveur est de fournir aux utilisateurs / serveurs distants un accès aux ressources internes, le serveur vous permet de déterminer le routage statique des clients vers le serveur et du serveur vers les clients. Du point de vue de l'accès client aux ressources internes, le serveur utilisant DHCP et les directives "route" ou "push route" permet de transférer des routes réseau internes au client. Pour notifier le serveur lui-même des réseaux distants côté client, le "répertoire de configuration client" (ccd) est utilisé, un mécanisme qui permet d'utiliser la directive "iroute" pour décrire la liste des réseaux internes client qui doivent se trouver dans la table de routage du serveur pour acheminer le trafic vers eux.
Sur cette fin «régulière» des fonctionnalités largement utilisées et la personnalisation locale pour chaque cas spécifique commence.
Fonctionnalités OpenVPN supplémentaires
Considérez les fonctionnalités supplémentaires d'OpenVPN, dont quelqu'un a peut-être entendu parler, mais en réalité n'a pas vu ou utilisé.
Sécurité réseau / filtrage de paquets
Parce que OpenVPN achemine le trafic, il a deux modes de fonctionnement réguliers mutuellement exclusifs. Le premier mode est le routage à l'intérieur du serveur OpenVPN, le deuxième mode est le routage nucléaire inter-interface. Dans le premier cas, OpenVPN est responsable de la commutation et du filtrage des paquets entre les clients / réseaux, dans le second cas, tout filtre de paquets système pris en charge sur l'hôte (pf, iptables, etc.).
Peu de gens savent qu'OpenVPN possède un filtre de paquets intégré qui vous permet d'autoriser ou d'isoler les connexions entre les utilisateurs et les réseaux.
Oui oui Vous avez bien lu. OpenVPN a son propre filtre de paquets intégré. La possibilité de filtrer le trafic a été mise en place en 2010 .
Le filtre de paquets OpenVPN est contrôlé soit via l'interface de gestion, soit via des plug-ins connectés à OpenVPN.
Les règles de circulation sont gérées via un fichier. Le format de fichier est simple.
[CLIENTS DROP|ACCEPT] {+|-}common_name1 {+|-}common_name2 . . . [SUBNETS DROP|ACCEPT] {+|-}subnet1 {+|-}subnet2 . . . [END]
Les directives de bloc (ACCEPT / DENY) définissent l'action par défaut pour tous les clients non spécifiés à l'intérieur du bloc.
Par exemple, fichier pour le client user2
[CLIENTS DROP] +user1 [SUBNETS DROP] [END]
bloquera le trafic vers tous les utilisateurs et réseaux, mais autorisera le trafic vers le côté client1. Si user1 ne décrit pas explicitement l'autorisation de transférer le trafic vers user2, alors le trafic ira seulement dans une direction user2-> user1.
Ou un autre exemple.
Tout désactiver sauf l'accès entre les utilisateurs et le serveur DNS situé sur le réseau local et le circuit de test sur le réseau 192.168.0.0/24
[CLIENTS DROP] +user1 +user2 [SUBNETS DROP] +10.150.0.1 +10.150.1.1 +192.168.0.0/24 [END]
Le mécanisme de filtrage est activé via le fichier de configuration, ou lors de la connexion du plugin qui "positionne" le drapeau "OPENVPN_PLUGIN_ENABLE_PF".
Nous discuterons de cette opportunité plus tard.
Le deuxième mode de filtrage du trafic est le filtre de paquets intégré au système. Pour l'activer, la configuration ne doit pas avoir de directive "client à client". Du point de vue de l'automatisation de l'activation / désactivation des règles nécessaires lors de la connexion / déconnexion des clients, il est plus pratique d'utiliser des insertions distinctes dans la liste des règles, implémentées soit via CHAINS dans Iptables (Linux) ou dans Anchors dans PF (FreeBSD). L'activation / désactivation des règles se fait généralement via les directives client-connect / client-déconnect du fichier de configuration du serveur, qui appellent les scripts correspondants lorsque l'utilisateur se connecte / se déconnecte.
Authentification PAM avancée
L'authentification PAM étendue signifie changer la logique de la connexion de l'utilisateur et la vérification du mot de passe. Ceci est réalisé soit en installant les plug-ins appropriés pour OpenVPN, qui fournissent la lecture et la vérification des données dans des sources externes, soit en connectant des bibliothèques au système qui permettent à toute logique d'être scriptée. L'une de ces bibliothèques est pam_python , qui aide à scripter toute logique de vérification de connexion / mot de passe via des scripts Python.
S'il est utilisé, la chaîne de vérification de l'utilisateur change comme suit.
plugin openvpn-plugin-auth-pam.so pam_python login USERNAME password PASSWORD domain mydomain.com
Les «sous le capot» de PAM étant les algorithmes de dialogue du système avec l'utilisateur ou les bibliothèques externes, ces dialogues peuvent être contrôlés. Par exemple, connectez les jetons OTP au système . La bibliothèque LinOTP est simplement prise comme exemple, car J'ai perdu ma propre bibliothèque auto-écrite lors des tests quelque part ¯ \ (ツ) / ¯
En outre, des exemples sont facilement googlé par le mot "pam_python".
Le principal problème lorsque vous travaillez avec des modules PAM externes est l'impossibilité d'obtenir l'environnement de session OpenVPN à l'intérieur du Python appelé ou de tout autre script appelé via le pam système. C'est-à-dire le script ne fournit que les fonctions de vérification du login / mot de passe qui lui sont attribuées.
Authentification différée
Le serveur OpenVPN prend en charge l'authentification dite "différée". L'authentification «différée» est utilisée dans les cas où le service d'authentification ne peut pas traiter la demande de vérification de connexion / mot de passe en temps réel.
Plugins OpenVPN
Il s'agit d'un univers parallèle séparé, sur lequel il peut être connu, mais en raison d'une certaine confusion, ils ne peuvent pas ou ont peur d'utiliser. En effet, écrire un plug-in fonctionnel pour OpenVPN nécessite une programmation en C avec tout ce que cela implique. Des exemples de plugins simples sont inclus dans l'arborescence source d'OpenVPN, ou par exemple, il existe un plugin pour démontrer les appels de méthode depuis OpenVPN .
Essayons de comprendre comment les plugins fonctionnent à partir d'OpenVPN.
Les fonctions et paramètres utilisés pour travailler avec les plugins sont décrits dans un fichier séparé
La tâche principale du plugin, lorsqu'il est initialisé par le serveur OpenVPN, est de transférer la liste des fonctions prises en charge par le plugin et, lors de l'appel de l'une des fonctions, de renvoyer le code de réponse correct, qui sera clair pour le serveur.
#define OPENVPN_PLUGIN_FUNC_SUCCESS 0 #define OPENVPN_PLUGIN_FUNC_ERROR 1 #define OPENVPN_PLUGIN_FUNC_DEFERRED 2
Arrêtons-nous plus en détail sur chaque groupe. Nous considérerons la logique de travail basée sur l'authentification par mot de passe de l'utilisateur.
Au démarrage du serveur, après lecture du fichier de configuration, le serveur appelle les fonctions OPENVPN_PLUGIN_UP et OPENVPN_PLUGIN_ROUTE_UP. Dans l'environnement variable des fonctions appelées, les principaux paramètres du serveur en cours d'exécution sont transférés.
OPENVPN_PLUGIN_UP { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "daemon_log_redirect":"1", "daemon":"1", "route_net_gateway":"172.16.100.1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"0", "local_port_1":"1200", "route_network_1":"10.150.0.0" }
OPENVPN_PLUGIN_ROUTE_UP { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "daemon_log_redirect":"1", "daemon":"1", "route_net_gateway":"172.16.100.1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"2", "local_port_1":"1200", "route_network_1":"10.150.0.0" }
Ces fonctions peuvent être utilisées pour les alertes au démarrage du serveur ou les changements de configuration.
Lors de la connexion d'un client, OpenVPN demande la possibilité d'activer un filtre de paquets interne.
OPENVPN_PLUGIN_ENABLE_PF { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "daemon":"1", "daemon_log_redirect":"1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"11", "local_port_1":"1200", "route_network_1":"10.150.0.0" }
Comme vous pouvez le voir sur le vidage, la variable pf_file est apparue. Ce fichier doit contenir les règles du filtre de paquets interne pour la session en cours de traitement.
Ensuite, le nom d'utilisateur et le mot de passe de l'utilisateur sont vérifiés dans la fonction OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "IV_NCP":"2", "IV_COMP_STUB":"1", "daemon_start_time":"1545994898", "IV_LZ4":"1", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_a3d0650a43b88ca1b5f305ce2c8f682.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"2", "IV_PLAT":"win", "daemon_pid":"626", "password":"12312312312312", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"5", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" }
C'est le seul endroit où le mot de passe dans l'environnement variable est présent en clair.
Le résultat de cette fonction devrait être trois réponses possibles.
#define OPENVPN_PLUGIN_FUNC_SUCCESS 0 #define OPENVPN_PLUGIN_FUNC_ERROR 1 #define OPENVPN_PLUGIN_FUNC_DEFERRED 2
Si le serveur reçoit une réponse OPENVPN_PLUGIN_FUNC_DEFERRED, alors le mécanisme d'authentification "retardée" entre en action. Comme on le voit, la variable "auth_control_file" est apparue dans l'environnement variable, le contenu de cette variable contient le nom du fichier dans lequel une réponse du système d'authentification sera attendue. La réponse est le symbole 0 (pour autoriser l'accès), 1 (pour refuser l'accès) placé dans le fichier spécifié. Le paramètre serveur "hand-window" détermine le délai d'expiration en secondes, pendant lequel le serveur attendra une réponse. Pendant l'attente, le trafic provenant d'autres clients n'est pas interrompu.
Puisque nous travaillons avec l'authentification par mot de passe, la fonction de vérification de certificat OPENVPN_PLUGIN_TLS_VERIFY n'est pas appelée. Au lieu de cela, OPENVPN_PLUGIN_TLS_FINAL est appelé immédiatement, confirmant l'établissement de la session.
OPENVPN_PLUGIN_TLS_FINAL { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "IV_NCP":"2", "IV_COMP_STUB":"1", "daemon_start_time":"1545994898", "IV_LZ4":"1", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_a3d0650a43b88ca1b5f305ce2c8f682.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"2", "IV_PLAT":"win", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"10", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" }
Ensuite, l'appel OPENVPN_PLUGIN_IPCHANGE est appelé, qui est appelé avant de changer l'adresse IP du client.
OPENVPN_PLUGIN_IPCHANGE { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "redirect_gateway":"0", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "ifconfig_remote":"10.150.0.2", "IV_NCP":"2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_321bb12075dc0e1b5440d227220bac5d.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"3", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" }
La fonction OPENVPN_PLUGIN_CLIENT_CONNECT_V2 est appelée lorsque l'adresse IP est définie par le serveur DHCP interne.
OPENVPN_PLUGIN_CLIENT_CONNECT_V2 { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "dev":"tun150", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "time_ascii":"Sat Jan 12 18:54:48 2019", "ifconfig_remote":"10.150.0.2", "IV_NCP":"2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_321bb12075dc0e1b5440d227220bac5d.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "time_unix":"1547319288", "redirect_gateway":"0", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "ifconfig_pool_local_ip":"10.150.0.5", "pluginid":"9", "ifconfig_pool_remote_ip":"10.150.0.6", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" }
Dans un environnement variable, des variables apparaissent contenant les paramètres du tunnel "ifconfig_pool_local_ip" et "ifconfig_pool_remote_ip".
La fonction OPENVPN_PLUGIN_LEARN_ADDRESS est appelée lorsque le serveur OpenVPN apprend la connexion des adresses IP et les achemine vers celles-ci. Après avoir quitté cette fonction, la procédure d'application des paramètres de filtrage de paquets à partir du fichier est activée. La variable d'environnement OPENVPN_PLUGIN_LEARN_ADDRESS correspond dans ce cas à la phase OPENVPN_PLUGIN_CLIENT_CONNECT_V2.
fa56bf61-.../172.16.111.168:1200 ----- pf_check_reload : struct pf_context ----- fa56bf61-.../172.16.111.168:1200 enabled=1 fa56bf61-.../172.16.111.168:1200 filename='/tmp/openvpn_pf_343330698e4acdea34c8a8c7fb87d861.tmp' fa56bf61-.../172.16.111.168:1200 file_last_mod=1547319124 fa56bf61-.../172.16.111.168:1200 n_check_reload=1 fa56bf61-.../172.16.111.168:1200 reload=[1,15,1547319125] fa56bf61-.../172.16.111.168:1200 ----- struct pf_set ----- fa56bf61-.../172.16.111.168:1200 kill=0 fa56bf61-.../172.16.111.168:1200 ----- struct pf_subnet_set ----- fa56bf61-.../172.16.111.168:1200 default_allow=ACCEPT fa56bf61-.../172.16.111.168:1200 ----- struct pf_cn_set ----- fa56bf61-.../172.16.111.168:1200 default_allow=DROP fa56bf61-.../172.16.111.168:1200 12345678-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 fa56bf61-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 ---------- fa56bf61-.../172.16.111.168:1200 fa56bf61-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 12345678-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 --------------------
Lorsqu'un client est déconnecté, la fonction OPENVPN_PLUGIN_CLIENT_DISCONNECT est appelée.
OPENVPN_PLUGIN_CLIENT_DISCONNECT { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "dev":"tun150", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "time_ascii":"Sat Jan 12 18:54:48 2019", "bytes_received":"30893", "IV_NCP":"2", "untrusted_port":"1200", "ifconfig_remote":"10.150.0.2", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_4bdddbada2885cde42cd3cb1b85d77e5.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "time_unix":"1547319288", "redirect_gateway":"0", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "time_duration":"3781", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "bytes_sent":"22684", "remote_port_1":"1200", "ifconfig_pool_local_ip":"10.150.0.5", "pluginid":"7", "ifconfig_pool_remote_ip":"10.150.0.6", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" }
Dans un environnement variable, la durée de connexion et le trafic utilisateur sont ajoutés.
Comme vous pouvez le voir, en raison de l'abondance de données dans différents appels, l'écriture et le débogage d'un plug-in dans le langage de programmation C (C ++) sera une tâche assez longue.
Pour étendre la fonctionnalité, il a été décidé de faire un "miracle" d'abord pour le projet interne, puis de le mettre dans le domaine public :)
Après une longue lecture des codes source OpenVPN et divers exemples de plugins hautement spécialisés, un projet a été écrit qui utilise Python comme langage de programmation pour la logique de traitement de session. Le code est un plug-in en langage C qui se connecte à OpenVPN, qui envoie toutes les requêtes au plug-in, envoie le module à Python via la référence c-api .
Proxy python du plugin OpenVPN
Pourquoi le module Python?
La référence c-api Python travaillant directement avec des fichiers python ne fonctionne pas correctement avec le chargement de bibliothèques python.
Comment ça marche?
Lorsque le plugin est initialisé dans OpenVPN, le plugin renvoie une liste masquée de toutes les fonctions qu'il peut servir. Lorsque la prochaine phase de connexion ou événement interne se produit, OpenVPN appelle les fonctions correspondantes à partir du plugin. Le plugin convertit la variable d'environnement et les paramètres passés à la fonction en une structure, initialise python et passe la structure à la procédure correspondante du module python. La procédure renvoie l'une des trois réponses au plugin (0 - Succès, 1 - Erreur, 2 - Différé). La réponse est transformée et renvoyée par OpenVPN.
Veuillez noter que tous les appels de module sont "sans état", ce qui signifie que les procédures ne se souviennent pas et ne savent pas ce qui s'est passé plus tôt dans les autres appels. Vous ne pouvez vous concentrer que sur l'environnement variable transmis au plugin depuis OpenVPN.
À l'intérieur du module python, vous pouvez implémenter n'importe quelle logique en connectant les bibliothèques et les ressources nécessaires. Si vous n'êtes pas sûr de la vitesse des contrôles, utilisez les confirmations «en attente».
En utilisant le regroupement des utilisateurs connectés au service, grâce à pf_file, vous pouvez régler avec précision l'interaction réseau entre les utilisateurs et d'autres ressources. À son tour, en connectant le plug-in pour la surveillance, il sera toujours possible de gérer les sessions client via l'interface de gestion OpenVPN.
Pendant les tests du projet, un mécanisme de génération de mot de passe a été développé, similaire aux jetons jwt, mais avec une taille plus petite.
Le point est simple. Le jeton contient l'identifiant client et la date d'expiration de l'accès. Pour signer le jeton, HMAC_SHA1 avec une clé privée est utilisé. Une fois le jeton signé, le contenu du texte est corrompu par la signature et converti en base64. Ainsi, le "scellement" du jeton est obtenu. Un jeton scellé est utilisé comme mot de passe de l'utilisateur. Si un changement non autorisé d'un bloc de données se produit, xor se casse, si xor se brise, alors la vérification de la signature se rompt. Sans clé privée, la signature ne peut pas être modifiée.
Si vous ne souhaitez pas contrôler l'heure de validité du mot de passe avec vos mains, générez un tel jeton et vérifiez la validité à l'intérieur du plugin sans appeler de services externes. Ce schéma est très pratique pour la génération de mot de passe de session pendant un certain temps. Dans le même temps, vous pouvez transférer le contenu du jeton vers un système de contrôle externe et il se configurera pour déconnecter l'utilisateur après l'expiration du jeton.
J'espère que les informations contenues dans cet article vous ont été utiles.
Merci d'avoir pris le temps de le lire.
Si vous avez des questions, je vais essayer de répondre à ce que je peux.
© Aborche 2019
