#!/usr/bin/env python3 import os import sys import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText def check_env (member_id): """ Checks if wireguard is correctly installed, the script is run as root and the member id is correct. """ wgInstalled = os.system("wg") if os.geteuid() != 0: print("On a besoin des droits root pour créer un accès VPN.") print("Relancez la commande préfixée d'un sudo.") raise Exception("Got root?") if wgInstalled != 0: print("Wireguard ne semble pas être installé sur votre système.") print("Il faudrait installer wireguard-tools et wireguard-dkms avant\ d'utiliser ce script") raise Exception("Install wg") if member_id == 0 and member_id < 255: print("On est parti du principe que les IDs des membres commencent à 1.") print("Ah, aussi, pour le moment, on est aussi partis du principe que ça \ s'arrête à 254.") print("Si on a plus de 254 membres, premièrement, FÉLICITATIONS venant\ du Félix du passé. Par contre, il faut repenser l'adressage des \ IPs du VPN maintenant :( Ranson du succès j'immagine.") raise Exception("Wrong member_id") def gen_wg_keys (member_id, key_dir): """ Generates both the private and the public wireguard key of the new member. """ privkey_path = os.path.join(key_dir,"{0}.key".format(member_id)) pubkey_path = os.path.join(key_dir,"{0}.public".format(member_id)) gen_key_cmd = "wg genkey | tee {0} | wg pubkey > {1}".format(privkey_path, pubkey_path) if os.system(gen_key_cmd) != 0: print("Erreur lors de la génération des clés wireguard.") print("Contactez un administrateur technique en lui envoyant le message d'erreur ci-dessus.") sys.exit(1) return (privkey_path, pubkey_path) def create_wg_config (member_id, config_dir, wg_server_privkey, pubkey_path): """ Generate the wireguard configuration for this new member. """ wg_filename = os.path.join (config_dir, "wg{0}.conf".format(member_id)) with open(pubkey_path, "r") as pub_file: wg_peer_pubkey = pub_file.read() wg_config = ''' [Interface] PrivateKey = {0} ListenPort = 51820 [Peer] PublicKey = {1} AllowedIPs = 0.0.0.0/24 '''.format(wg_server_privkey, wg_peer_pubkey) with open(wgFileName, "w") as wg_file: wg_file.write(wg_config) def create_if_file (member_id, config_dir): """ Create and configure the new network interface for this new member. """ iface_name = "wg{0}".format(member_id) iface_addrv4 = "10.0.0.{0}".format(member_id) iface_filename = os.path.join (config_dir, "{}.conf".format(iface_name)) iface_config = ''' auto {0} iface {0} inet static address {1} netmask 255.255.255.0 pre-up ip link add $IFACE type wireguard pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf post-down ip link del $IFACE '''.format(iface_name, iface_addrv4) with open(iface_filename, "w") as iface_file: iface_file.write(iface_config) class Email: """ Not really necessary, but I keep on forgetting most of an email arguments and I'm tired of debugging this class of error... Too bad we don't have any record type in this language. PS: I hate python. """ def __init__(self, username, passwd, from_addr, to_addr, server): self.username = username self.passwd = passwd self.from_addr = from_addr self.to_addr = to_addr self.server = server def send_mail(email, wgconfig): """ Send the private key by email. email: - username - passwd - from_addr - to_addr - server """ from_addr = 'bureau@baionet.fr' password = email.passwd msg = MIMEMultipart() msg['Subject'] = "Votre acces VPN Baionet" msg['From'] = email.from_addr msg['To'] = [email.to_addr] body = ''' blahblah, cf le wiki blahblahblah ''' mail_static_text = random.choice(messages) msg.attach([MIMEText(body), MIMEText(config)]) username = email.username server = smtplib.SMTP(email.server) server.ehlo() server.starttls() server.login(email.username, email.passwd) server.sendmail(email.from_addr, email.to_addr, msg.as_string()) server.quit() # Main Function # ============= # ************* # ============= # 1- Parse email/member id. # 2- Génère les clés wireguard. # 3- Crée/déploie la configuration wireguard. # 4- Crée/déploie la nouvelle interface réseau. # 5- Envoie la clé à l'utilisateur (email/manuellement) if __name__ == '__main__': key_dir = "/etc/wireguard/keys" wg_config_dir = "/etc/wireguard" if_config_dir = "/etc/interfaces" # On récupère le numéro d'adhérant et l'email d'un nouveau membre. member_email = input("EMail du nouveau membre: ") try: member_id = int(input("Numéro d'adhérant du nouveau membre: ")) except Exception as e: print("ERREUR: Le numéro d'adhérant est en théorie un entier entre 1 et 254.") try: check_env(member_id) except Exception as e: print("ERREUR: problème d'environnement: {}".format(e)) sys.exit(1) print("[+] Génération des clés wireguard") (privkey_path,pubkey_path) = gen_wg_keys(member_id, tmp_key_dir) print("[+] Création de la configuration wireguard") create_wg_config(member_id, wg_config_dir, privkey_path, pubkey_path) print("[+] Création de la nouvelle interface réseau") create_if_file(member_id, if_config_dir) print("[+] Chargement de la nouvelle interface réseau") os.system("systemctl restart networking") print("[+] Envoi de la clé privée au nouveau membre") try: username = os.environ['SMTP_USERNAME'] passwd = os.environ['SMTP_PASSWD'] server = os.environ['SMTP_SERVER'] email = Email(username, passwd, "bureau@baionet.fr", member_email, "smtp://server") send_email(email, privkey_path, "") except Exception as e: print("ERREUR: erreur lors de l'envoi de l'email: {}".format(e)) print("Veuillez envoyer tout ce message d'erreur à la liste bayonetek@framalistes.org") sys.exit(1) print("[+] Nettoyage") print("[+] DONE")