|
@@ -1,55 +1,174 @@
|
|
|
-#!/usr/bin/env python
|
|
|
+#!/usr/bin/env python3
|
|
|
|
|
|
import os
|
|
|
+import sys
|
|
|
+import smtplib
|
|
|
+from email.mime.multipart import MIMEMultipart
|
|
|
+from email.mime.text import MIMEText
|
|
|
|
|
|
-# TODO: récupérer email et id depuis STDIN.
|
|
|
-keyDir = "/etc/wireguard/keys"
|
|
|
-configDir = "/etc/wireguard"
|
|
|
-
|
|
|
-# IO:
|
|
|
-# (mail)
|
|
|
-# (dossier clés)
|
|
|
-# (dossier config)
|
|
|
-# 1- Créer clé pv pb
|
|
|
-pvKeyDest = "/etc/wireguard/keys/ohian.key"
|
|
|
-pubKeyDest = "/etc/wireguard/keys/ohian.public"
|
|
|
-
|
|
|
-
|
|
|
-genKeyCommand = "wg genkey | tee {0} | wg pubkey > {1}".format(pvKeyDest, pubKeyDest)
|
|
|
-genKeyCommand = "wg genkey | tee /etc/wireguard/keys/ohian.key | wg pubkey > /etc/wireguard/keys/ohian.public"
|
|
|
-os.system(genKeyCommand)
|
|
|
-
|
|
|
-# 2- Créer fichier interface
|
|
|
-ifaceName = "wg10"
|
|
|
-ifaceAddrv4 = "10.0.0.10"
|
|
|
-ifaceFileName = configDir + "/" + ifaceName + ".conf"
|
|
|
-ifaceConfig = '''
|
|
|
-auto {0}
|
|
|
-iface {1} inet static
|
|
|
- address {2}
|
|
|
- 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(ifaceName, ifaceName, ifaceAddrv4)
|
|
|
-ifaceFile = os.open(ifaceFileName, "w")
|
|
|
-ifaceFile.write(ifaceStr)
|
|
|
-ifaceFile.close()
|
|
|
-# 3- Créer config wg
|
|
|
-#
|
|
|
-wgFileName = ""
|
|
|
-wgPeerPubKey = ""
|
|
|
-wgPrivKey = ""
|
|
|
-wgConfig = '''
|
|
|
-[Interface]
|
|
|
-PrivateKey = {0}
|
|
|
-ListenPort = 51820
|
|
|
-
|
|
|
-[Peer]
|
|
|
-PublicKey = {1}
|
|
|
-AllowedIPs = 0.0.0.0/24
|
|
|
-'''.format(wgPrivPubKey, wgPeerPubKey)
|
|
|
-wgFile = os.open(wgFileName, "w")
|
|
|
-wgFile.write(wgConfig)
|
|
|
-wgFile.close()
|
|
|
-# 4- Envoyer mail/afficher instructions
|
|
|
+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")
|