Browse Source

Extracted script stages in proper functions.

Félix Baylac-Jacqué 6 years ago
parent
commit
18beb3c7d4
1 changed files with 171 additions and 52 deletions
  1. 171 52
      wireguardCreate.py

+ 171 - 52
wireguardCreate.py

@@ -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")