Robin Thoni 8 роки тому
джерело
коміт
78b986324e

+ 14
- 4
vpngen-cli.py Переглянути файл

@@ -3,6 +3,7 @@
3 3
 from __future__ import print_function
4 4
 import argparse
5 5
 import json
6
+import os
6 7
 import sys
7 8
 import vpngen
8 9
 
@@ -14,7 +15,7 @@ def eprint(*args, **kwargs):
14 15
 def create_variables(variables, defaults):
15 16
     variables_set = defaults.copy()
16 17
     for variable in variables:
17
-        if variable == 'name':
18
+        if variable == 'name' or variable == 'client':
18 19
             continue
19 20
         default = variables_set[variable] if variable in variables_set else ''
20 21
         print("Enter a value for '%s' [%s]: " % (variable, default), end='', flush=True)
@@ -52,8 +53,14 @@ def main():
52 53
 
53 54
     vpng = vpngen.VpnGen(config['defaultConfigPath'], config['ovpnConfigPath'])
54 55
 
56
+    config_path = vpng.get_vpn_variables_path(vpn_name)
57
+    if os.path.exists(config_path):
58
+        with open(config_path, "r") as f:
59
+            data = json.load(f)
60
+        config['defaults'].update(data['variables'])
61
+
55 62
     if args.create:
56
-        variables = create_variables(vpng.get_vpn_vars(), config['defaults']['vpn'])
63
+        variables = create_variables(vpng.get_vpn_vars(), config['defaults'])
57 64
         res = vpng.create_vpn(vpn_name, variables)
58 65
         if res == vpngen.VpnGenError.Success:
59 66
             print("VPN %s created successfully" % vpn_name)
@@ -68,8 +75,11 @@ def main():
68 75
             eprint("Failed to remove VPN %s: %s" % (vpn_name, res))
69 76
             exit(1)
70 77
     elif args.create_client:
71
-        variables = create_variables(vpng.get_vpn_vars(), config['defaults']['vpn'])
72
-        res = vpng.create_client(vpn_name, client_name, variables)
78
+        variables = create_variables(vpng.get_client_vars(vpn_name), config['defaults'])
79
+        if variables is None:
80
+            res = vpngen.VpnGenError.VpnDoesNotExists
81
+        else:
82
+            res = vpng.create_client(vpn_name, client_name, variables)
73 83
         if res == vpngen.VpnGenError.Success:
74 84
             print("Client %s created successfully on VPN %s" % (client_name, vpn_name))
75 85
         else:

+ 169
- 33
vpngen.py Переглянути файл

@@ -1,3 +1,4 @@
1
+import json
1 2
 from enum import Enum
2 3
 import os
3 4
 import os.path
@@ -17,11 +18,13 @@ class VpnGenError(Enum):
17 18
 class VpnGen:
18 19
     default_config_base_dir = ""
19 20
     default_config_file = ""
21
+    default_client_config_file = ""
20 22
     ovpn_config_path = ""
21 23
 
22 24
     def __init__(self, default_config_path, ovpn_config_path):
23 25
         self.default_config_base_dir = os.path.abspath(default_config_path)
24 26
         self.default_config_file = "%s.conf" % self.default_config_base_dir
27
+        self.default_client_config_file = "%s%sclients%sclient.conf" % (self.default_config_base_dir, os.sep, os.sep)
25 28
         self.ovpn_config_path = os.path.abspath(ovpn_config_path)
26 29
 
27 30
     def f7(self, seq):
@@ -29,42 +32,86 @@ class VpnGen:
29 32
         seen_add = seen.add
30 33
         return [x for x in seq if not (x in seen or seen_add(x))]
31 34
 
32
-    def _find_vars(self, content):
33
-        variables = re.findall('\$\{([^}]+)}', content)
34
-        variables = self.f7(variables)
35
-        return variables
36
-
37 35
     def get_vpn_vars(self):
38 36
         with open(self.default_config_file, "r") as f:
39 37
             default_config = f.read()
40
-        variables = self._find_vars(default_config)
38
+
39
+        variables = re.findall('\$\{([^}]+)}', default_config)
41 40
         variables += ["KEY_COUNTRY", "KEY_PROVINCE", "KEY_CITY", "KEY_ORG", "KEY_EMAIL"]
41
+        variables = self.f7(variables)
42
+
42 43
         return variables
43 44
 
44
-    def create_vpn(self, vpn_name, variables):
45
-        base_dir = "%s%s%s" % (self.ovpn_config_path, os.sep, vpn_name)
46
-        conf_file = "%s.conf" % base_dir
47
-        if os.path.exists(base_dir) or os.path.exists(conf_file):
48
-            return VpnGenError.VpnAlreadyExists
45
+    def get_client_vars(self, vpn_name):
46
+        default_client_config_path = self.get_client_default_config_path(vpn_name)
47
+        if not os.path.exists(default_client_config_path):
48
+            return None
49 49
 
50
-        with open(self.default_config_file, "r") as f:
50
+        with open(default_client_config_path, "r") as f:
51 51
             default_config = f.read()
52
+        variables = re.findall('\$\{([^}]+)}', default_config)
53
+        variables = self.f7(variables)
52 54
 
53
-        variables['name'] = vpn_name
54
-        for variable in variables:
55
-            default_config = default_config.replace("${%s}" % variable, variables[variable])
55
+        return variables
56 56
 
57
-        os.makedirs(base_dir)
58
-        with open(conf_file, "w") as f:
59
-            f.write(default_config)
57
+    def get_base_dir(self, vpn_name):
58
+        return "%s%s%s%s" % (self.ovpn_config_path, os.sep, vpn_name, os.sep)
60 59
 
61
-        os.rmdir(base_dir)
62
-        shutil.copytree(self.default_config_base_dir, base_dir)
60
+    def get_config_path(self, vpn_name):
61
+        return "%s%s%s.conf" % (self.ovpn_config_path, os.sep, vpn_name)
63 62
 
64
-        curdir = os.curdir
65
-        easyrsadir = base_dir + os.sep + "easy-rsa" + os.sep
66
-        pkitool = easyrsadir + "pkitool"
67
-        os.chdir(easyrsadir)
63
+    def get_vpn_variables_path(self, vpn_name):
64
+        base_dir = self.get_base_dir(vpn_name)
65
+        return "%svpngen.json" % base_dir
66
+
67
+    def get_easy_rsa_dir(self, vpn_name):
68
+        base_dir = self.get_base_dir(vpn_name)
69
+        return "%seasy-rsa%s" % (base_dir, os.sep)
70
+
71
+    def get_easy_rsa_key_dir(self, vpn_name):
72
+        easyrsadir = self.get_easy_rsa_dir(vpn_name)
73
+        return "%skeys%s" % (easyrsadir, os.sep)
74
+
75
+    def get_pkitool_path(self, vpn_name):
76
+        easyrsadir = self.get_easy_rsa_dir(vpn_name)
77
+        return "%spkitool" % easyrsadir
78
+
79
+    def get_client_default_config_path(self, vpn_name):
80
+        base_dir = self.get_base_dir(vpn_name)
81
+        return "%s%sclients/client.conf" % (base_dir, os.sep)
82
+
83
+    def get_client_dir(self, vpn_name, client_name):
84
+        base_dir = self.get_base_dir(vpn_name)
85
+        return "%sclients%s%s%s" % (base_dir, os.sep, client_name, os.sep)
86
+
87
+    def get_client_config_path(self, vpn_name, client_name):
88
+        client_dir = self.get_client_dir(vpn_name, client_name)
89
+        return "%s%s-%s.conf" % (client_dir, client_name, vpn_name)
90
+
91
+    def get_client_generated_files_paths(self, vpn_name, client_name):
92
+        keys_dir = self.get_easy_rsa_key_dir(vpn_name,)
93
+        return [
94
+            "%s%s.crt" % (keys_dir, client_name),
95
+            "%s%s.key" % (keys_dir, client_name)
96
+        ]
97
+
98
+    def get_client_tarball_path(self, vpn_name, client_name):
99
+        base_dir = self.get_base_dir(vpn_name)
100
+        return "%sclients%s%s-%s.tar.bz2" % (base_dir, os.sep, client_name, vpn_name)
101
+
102
+    def get_server_needed_files_paths(self, vpn_name):
103
+        keys_dir = self.get_easy_rsa_key_dir(vpn_name)
104
+        return [
105
+            "%sca.crt" % keys_dir,
106
+            "%sta.key" % keys_dir
107
+        ]
108
+
109
+    def get_all_needed_files_paths(self, vpn_name, client_name):
110
+        return self.get_client_generated_files_paths(vpn_name, client_name) +\
111
+               self.get_server_needed_files_paths(vpn_name)
112
+
113
+    def setup_vars(self, vpn_name, variables):
114
+        easyrsadir = self.get_easy_rsa_dir(vpn_name)
68 115
 
69 116
         os.environ["KEY_COUNTRY"] = variables['KEY_COUNTRY']
70 117
         os.environ["KEY_PROVINCE"] = variables['KEY_PROVINCE']
@@ -82,23 +129,60 @@ class VpnGen:
82 129
         os.environ["OPENSSL"] = "openssl"
83 130
         os.environ["PKCS11TOOL"] = "pkcs11-tool"
84 131
         os.environ["GREP"] = "grep"
85
-        os.environ["KEY_CONFIG"] = easyrsadir + "openssl.cnf"
86
-        os.environ["KEY_DIR"] = easyrsadir + "keys"
132
+        os.environ["KEY_CONFIG"] = "%s%s" % (easyrsadir, "openssl.cnf")
133
+        os.environ["KEY_DIR"] = "%s%s" % (easyrsadir, "keys")
87 134
         os.environ["PKCS11_MODULE_PATH"] = "dummy"
88 135
         os.environ["PKCS11_PIN"] = "dummy"
89 136
 
90
-        call(["./clean-all"])
137
+    def create_vpn(self, vpn_name, variables):
138
+        base_dir = self.get_base_dir(vpn_name)
139
+        conf_file = self.get_config_path(vpn_name)
140
+        conf_vpngen_file = self.get_vpn_variables_path(vpn_name)
141
+        if os.path.exists(base_dir) or os.path.exists(conf_file):
142
+            return VpnGenError.VpnAlreadyExists
143
+
144
+        with open(self.default_config_file, "r") as f:
145
+            default_config = f.read()
146
+
147
+        variables['name'] = vpn_name
148
+        for variable in variables:
149
+            default_config = default_config.replace("${%s}" % variable, variables[variable])
150
+
151
+        os.makedirs(base_dir)
152
+        with open(conf_file, "w") as f:
153
+            f.write(default_config)
154
+
155
+        os.rmdir(base_dir)
156
+        shutil.copytree(self.default_config_base_dir, base_dir)
157
+
158
+        curdir = os.curdir
159
+        easyrsadir = self.get_easy_rsa_dir(vpn_name)
160
+        pkitool = self.get_pkitool_path(vpn_name)
161
+        os.chdir(easyrsadir)
162
+
163
+        self.setup_vars(vpn_name, variables)
164
+
165
+        call([".%sclean-all" % os.sep])
91 166
         call([pkitool, "--initca"])
92 167
         call([pkitool, "server"])
93
-        call(["./build-dh"])
168
+        call([".%sbuild-dh" % os.sep])
169
+        call(["openssl", "ca", "-gencrl",
170
+              "-keyfile", "keys%sca.key" % os.sep,
171
+              "-cert", "keys%sca.crt" % os.sep,
172
+              "-out", "keys%crl.pem" % os.sep,
173
+              "-config", "openssl.cnf"])
174
+        call(["openvpn", "--genkey", "--secret", "keys%sta.key" % os.sep])
175
+
176
+        with open(conf_vpngen_file, "w") as f:
177
+            json.dump({'variables': variables}, f, indent=4, separators=(',', ': '))
94 178
 
95 179
         os.chdir(curdir)
96 180
 
97 181
         return VpnGenError.Success
98 182
 
99 183
     def remove_vpn(self, vpn_name):
100
-        base_dir = "%s%s%s" % (self.ovpn_config_path, os.sep, vpn_name)
101
-        conf_file = "%s.conf" % base_dir
184
+        base_dir = self.get_base_dir(vpn_name)
185
+        conf_file = self.get_config_path(vpn_name)
102 186
         if not os.path.exists(base_dir) and not os.path.exists(conf_file):
103 187
             return VpnGenError.VpnDoesNotExists
104 188
         os.remove(conf_file)
@@ -106,10 +190,62 @@ class VpnGen:
106 190
         return VpnGenError.Success
107 191
 
108 192
     def create_client(self, vpn_name, client_name, variables):
109
-        return VpnGenError.ClientDoesNotExists
193
+        base_dir = self.get_base_dir(vpn_name)
194
+        client_conf_file = self.get_client_config_path(vpn_name, client_name)
195
+        if not os.path.exists(base_dir):
196
+            return VpnGenError.VpnDoesNotExists
197
+        client_dir = self.get_client_dir(vpn_name, client_name)
198
+        if os.path.exists(client_dir):
199
+            return VpnGenError.ClientAlreadyExists
200
+
201
+        client_default_config_path = self.get_client_default_config_path(vpn_name)
202
+        with open(client_default_config_path, "r") as f:
203
+            client_default_config = f.read()
204
+
205
+        variables['name'] = vpn_name
206
+        variables['client'] = client_name
207
+        for variable in variables:
208
+            client_default_config = client_default_config.replace("${%s}" % variable, variables[variable])
209
+
210
+        os.makedirs(client_dir)
211
+        with open(client_conf_file, "w") as f:
212
+            f.write(client_default_config)
213
+
214
+        curdir = os.curdir
215
+        easyrsadir = self.get_easy_rsa_dir(vpn_name)
216
+        pkitool = self.get_pkitool_path(vpn_name)
217
+        os.chdir(easyrsadir)
218
+
219
+        self.setup_vars(vpn_name, variables)
220
+        os.environ["KEY_CN"] = client_name
221
+        os.environ["KEY_NAME"] = client_name
222
+
223
+        call([pkitool, client_name])
224
+
225
+        os.chdir(curdir)
226
+
227
+        files_paths = self.get_all_needed_files_paths(vpn_name, client_name)
228
+        for file_path in files_paths:
229
+            split = os.path.splitext(file_path)
230
+            dest = "%s%s-%s%s" % (client_dir, os.path.basename(split[0]), vpn_name, split[1])
231
+            shutil.copy(file_path, dest)
232
+
233
+        files_names = list(map(lambda file_path: os.path.basename(file_path), files_paths))
234
+
235
+        call(["tar", "cfj", self.get_client_tarball_path(vpn_name, client_name),
236
+              "-C", self.get_easy_rsa_key_dir(vpn_name)] + files_names)
237
+
238
+        return VpnGenError.Success
110 239
 
111 240
     def remove_client(self, vpn_name, client_name):
112
-        return VpnGenError.ClientDoesNotExists
241
+        base_dir = self.get_base_dir(vpn_name)
242
+        if not os.path.exists(base_dir):
243
+            return VpnGenError.VpnDoesNotExists
244
+        client_dir = self.get_client_dir(vpn_name, client_name)
245
+        if not os.path.exists(client_dir):
246
+            return VpnGenError.ClientDoesNotExists
247
+        return VpnGenError.Success
113 248
 
114 249
     def rebuild_clients(self, vpn_name):
115
-        return VpnGenError.ClientDoesNotExists
250
+        base_dir = self.get_base_dir(vpn_name)
251
+        return VpnGenError.Success

+ 7
- 7
vpngen/default.conf Переглянути файл

@@ -1,4 +1,4 @@
1
-# Server TCP/443
1
+# Server TCP on ${hostname}
2 2
 mode server
3 3
 proto tcp-server
4 4
 port ${port}
@@ -6,16 +6,16 @@ dev ${dev}
6 6
 client-to-client
7 7
 
8 8
 # Keys and certificates
9
-ca /etc/openvpn/${name}/ca.crt
10
-cert /etc/openvpn/${name}/server.crt
11
-key /etc/openvpn/${name}/server.key
12
-dh /etc/openvpn/${name}/dh1024.pem
13
-tls-auth /etc/openvpn/${name}/ta.key 1
9
+ca /etc/openvpn/${name}/keys/ca.crt
10
+cert /etc/openvpn/${name}/keys/server.crt
11
+key /etc/openvpn/${name}/keys/server.key
12
+dh /etc/openvpn/${name}/keys/dh1024.pem
13
+tls-auth /etc/openvpn/${name}/keys/ta.key 1
14 14
 
15 15
 key-direction 0
16 16
 cipher AES-256-CBC
17 17
 crl-verify /etc/openvpn/${name}/easy-rsa/keys/crl.pem
18
-client-config-dir /etc/openvpn/${name}/clientsconf
18
+client-config-dir /etc/openvpn/${name}/client-config-dir
19 19
 
20 20
 # Network
21 21
 server ${net} ${mask}

+ 0
- 0
vpngen/default/client-config-dir/.gitkeep Переглянути файл


+ 7
- 7
vpngen/default/clients/client.conf Переглянути файл

@@ -2,18 +2,18 @@
2 2
 client
3 3
 dev tun
4 4
 proto tcp-client
5
-remote 178.170.113.82 %%VPNPORT%%
5
+remote ${hostname} ${port}
6 6
 resolv-retry infinite
7 7
 cipher AES-256-CBC
8 8
 
9
-# Cles
10
-ca ca-%%VPNNAME%%.crt
11
-cert %%client%%-%%VPNNAME%%.crt
12
-key %%client%%-%%VPNNAME%%.key
13
-tls-auth ta-%%VPNNAME%%.key 1
9
+# Keys
10
+ca ca-${name}.crt
11
+cert ${client}-${name}.crt
12
+key ${client}-${name}.key
13
+tls-auth ta-${name}.key 1
14 14
 key-direction 1
15 15
 
16
-# Securite
16
+# Security
17 17
 nobind
18 18
 persist-key
19 19
 persist-tun

+ 15
- 20
vpngen/vpngen.json Переглянути файл

@@ -10,26 +10,21 @@
10 10
   "ovpnConfigPath": "/etc/openvpn",
11 11
 
12 12
   "defaults": {
13
-    "vpn": {
14
-      "port": "4242",
15
-      "hostname": "vpn.example.com",
16
-      "net": "10.0.0.0",
17
-      "mask": "255.255.255.0",
18
-      "dev": "tap",
19
-      "user": "root",
20
-      "group": "root",
13
+    "port": "4242",
14
+    "hostname": "vpn.example.com",
15
+    "net": "10.0.0.0",
16
+    "mask": "255.255.255.0",
17
+    "dev": "tap",
18
+    "user": "root",
19
+    "group": "root",
21 20
 
22
-      "KEY_COUNTRY": "COUNTRY",
23
-      "KEY_PROVINCE": "state",
24
-      "KEY_CITY": "City",
25
-      "KEY_ORG": "example",
26
-      "KEY_EMAIL": "root@example.com",
27
-      "KEY_SIZE": "1024",
28
-      "CA_EXPIRE": "3650",
29
-      "KEY_EXPIRE": "3650"
30
-    },
31
-    "client": {
32
-
33
-    }
21
+    "KEY_COUNTRY": "COUNTRY",
22
+    "KEY_PROVINCE": "state",
23
+    "KEY_CITY": "City",
24
+    "KEY_ORG": "example",
25
+    "KEY_EMAIL": "root@example.com",
26
+    "KEY_SIZE": "1024",
27
+    "CA_EXPIRE": "3650",
28
+    "KEY_EXPIRE": "3650"
34 29
   }
35 30
 }

Завантаження…
Відмінити
Зберегти