Last active
May 19, 2017 10:29
-
-
Save wnn/74d98041c4630f273680 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/python | |
# openssl dhparam -out dh2048.pem 2048 | |
# config example, example.ini | |
# [general] | |
# host = wnn.io | |
# offset = 0 | |
# [arbiter] | |
# static_ip_index = 1 | |
# [dmServer] | |
# static_ip_index = 2 | |
import subprocess | |
import os | |
import os.path | |
import shutil | |
from argparse import ArgumentParser | |
from ConfigParser import ConfigParser | |
current_path = os.path.dirname(os.path.abspath(__file__)) | |
path_easy_rsa = '/usr/share/easy-rsa' | |
path_clean_all = os.path.join(path_easy_rsa, "clean-all") | |
path_pkitool = os.path.join(path_easy_rsa, "pkitool") | |
path_openvpn = '/etc/openvpn' | |
def _make_sure_directory(path): | |
if not os.path.exists(path): | |
os.makedirs(path) | |
print("mkdir: %s" % path) | |
def _check_file(path, prefix): | |
if os.path.exists(path): | |
print("%s already exists: %s" % (prefix, path)) | |
return True | |
else: | |
return False | |
class ConfGenerator(object): | |
def __init__(self, name, offset, server_host): | |
self.env = os.environ | |
self._setup_env() | |
self.name = name | |
self.offset = offset | |
self.server_host = server_host | |
self.build_ca() | |
self.build_tls_auth() | |
def _setup_env(self): | |
env = self.env | |
env["EASY_RSA"] = path_easy_rsa | |
env["OPENSSL"] = "openssl" | |
env["PKCS11TOOL"] = "pkcs11-tool" | |
env["GREP"] = "grep" | |
p = os.path.join(path_easy_rsa, "whichopensslcnf") | |
args = [p, path_easy_rsa] | |
env["KEY_CONFIG"] = self._exec(args).strip() | |
env["PKCS11_MODULE_PATH"] = "dummy" | |
env["PKCS11_PIN"] = env["PKCS11_MODULE_PATH"] | |
env["KEY_SIZE"] = "2048" | |
env["CA_EXPIRE"] = "3650" | |
env["KEY_EXPIRE"] = env["CA_EXPIRE"] | |
env["KEY_COUNTRY"] = "CN" | |
env["KEY_PROVINCE"] = "Beijing" | |
env["KEY_CITY"] = "Beijing" | |
env["KEY_ORG"] = "Nuctech" | |
env["KEY_EMAIL"] = "[email protected]" | |
env["KEY_OU"] = "software" | |
@property | |
def offset(self): | |
return self._offset | |
@offset.setter | |
def offset(self, value): | |
value = int(value) | |
self._offset = value | |
self._server_port = 1194 + value | |
self._ip_prefix = "10.8.%s" % value | |
@property | |
def name(self): | |
return self._name | |
@name.setter | |
def name(self, value): | |
self._name = value | |
self._path_keys = os.path.join(current_path, "keys", value) | |
_make_sure_directory(self._path_keys) | |
self._path_confs = os.path.join(current_path, "conf", value) | |
_make_sure_directory(self._path_confs) | |
self.env["KEY_DIR"] = self._path_keys | |
self.env["KEY_NAME"] = value | |
self._path_ccd = os.path.join( | |
path_openvpn, | |
"%s_ccd" % value | |
) | |
_make_sure_directory(self._path_ccd) | |
def _exec(self, args, **kargs): | |
proc = subprocess.Popen( | |
args, stdin=subprocess.PIPE, | |
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, | |
env=self.env, | |
**kargs | |
) | |
o, e = proc.communicate() | |
return o | |
def build_ca(self): | |
self._path_ca = os.path.join(self._path_keys, "ca.crt") | |
if _check_file(self._path_ca, "ca"): | |
return | |
print("clean-all") | |
self._exec(path_clean_all) | |
print("run build-ca") | |
self._exec("%s --initca" % path_pkitool, shell=True) | |
def build_tls_auth(self): | |
self._path_tls = os.path.join(self._path_keys, "ta.key") | |
if _check_file(self._path_tls, "TLS-auth"): | |
return | |
print("build TLS-auth") | |
self._exec(['openvpn', '--genkey', '--secret', self._path_tls]) | |
def make_server(self): | |
self.build_server() | |
self.gen_server_conf() | |
def make_client(self, name, static_ip_index): | |
cname = "%s_%s" % (self.name, name) | |
path_key, path_crt = self.build_client(cname) | |
self.gen_client_conf(cname, path_key, path_crt) | |
path_ccd = os.path.join(self._path_ccd, cname+".new") | |
print("generate %s" % path_ccd) | |
index = int(static_ip_index) | |
client_ip = "%s.%s" % (self._ip_prefix, | |
4*index + 2) | |
endpoint = "%s.%s" % (self._ip_prefix, | |
4*index + 1) | |
with open(path_ccd, "w") as f: | |
f.write( | |
"ifconfig-push %s %s" % (client_ip, endpoint) | |
) | |
def build_server(self): | |
self._path_server_key = os.path.join( | |
self._path_keys, "%s.key" % self.name) | |
self._path_server_crt = self._path_server_key.replace('.key', '.crt') | |
if _check_file(self._path_server_key, "server"): | |
return | |
print("build server") | |
self._exec( | |
"%s --server %s" % (path_pkitool, self.name), | |
shell=True) | |
def build_client(self, cname): | |
path_client_key = os.path.join(self._path_keys, "%s.key" % cname) | |
path_client_crt = os.path.join(self._path_keys, "%s.crt" % cname) | |
if _check_file(path_client_key, cname): | |
return path_client_key, path_client_crt | |
print("build client: %s" % cname) | |
self._exec( | |
"%s %s" % (path_pkitool, cname), | |
shell=True) | |
return path_client_key, path_client_crt | |
def gen_client_conf(self, cname, path_key, path_crt): | |
path_conf = os.path.join(self._path_confs, "%s.conf" % cname) | |
print("gen client conf: %s" % path_conf) | |
with open(path_conf, "w") as dst: | |
dst.write("""remote %s %s | |
client | |
dev tun | |
proto udp | |
resolv-retry infinite | |
nobind | |
user nobody | |
group nogroup | |
persist-key | |
persist-tun | |
ns-cert-type server | |
comp-lzo | |
mssfix 1400 | |
cipher AES-256-CBC | |
verb 3 | |
""" % (self.server_host, self._server_port)) | |
template = [ | |
(self._path_ca, '<ca>\n%s</ca>\n\n'), | |
(path_crt, '<cert>\n%s</cert>\n\n'), | |
(path_key, '<key>\n%s</key>\n\n'), | |
(self._path_tls, | |
'key-direction 1\n<tls-auth>\n%s</tls-auth>\n\n') | |
] | |
for fname, ft in template: | |
with open(fname) as src: | |
dst.write(ft % src.read()) | |
def gen_server_conf(self): | |
path_conf = os.path.join(self._path_confs, "%s.conf" % self.name) | |
print("gen server conf: %s" % path_conf) | |
with open(path_conf, "w") as dst: | |
dst.write("""port %s | |
server %s.0 255.255.255.0 | |
client-config-dir %s | |
ccd-exclusive | |
status /var/log/openvpn-%s-status.log | |
log /var/log/openvpn-%s.log | |
proto udp | |
dev tun | |
dh dh2048.pem | |
client-to-client | |
user nobody | |
group nogroup | |
keepalive 10 120 | |
comp-lzo | |
persist-key | |
persist-tun | |
cipher AES-256-CBC | |
verb 3 | |
""" % (self._server_port, self._ip_prefix, | |
self._path_ccd, self.name, self.name)) | |
template = [ | |
(self._path_ca, '<ca>\n%s</ca>\n\n'), | |
(self._path_server_crt, '<cert>\n%s</cert>\n\n'), | |
(self._path_server_key, '<key>\n%s</key>\n\n'), | |
(self._path_tls, | |
'key-direction 0\n<tls-auth>\n%s</tls-auth>\n\n') | |
] | |
for fname, ft in template: | |
with open(fname) as src: | |
dst.write(ft % src.read()) | |
path_dst = os.path.join(path_openvpn, "%s.conf.new" % self.name) | |
print("try to deploy: %s" % path_dst) | |
shutil.copyfile(path_conf, path_dst) | |
print("done") | |
def gen_from_cfg(name, cfg): | |
clients = [] | |
for sec in cfg.sections(): | |
if sec == 'general': | |
host = cfg.get(sec, 'host') | |
offsect = cfg.get(sec, 'offset') | |
else: | |
static_ip_index = cfg.get(sec, 'static_ip_index') | |
clients.append((sec, static_ip_index)) | |
gen = ConfGenerator(name, offsect, host) | |
gen.make_server() | |
for client_name, static_ip_index in clients: | |
gen.make_client(client_name, static_ip_index) | |
def main(): | |
parser = ArgumentParser( | |
description="Generate openvpn conf from config ini.") | |
parser.add_argument('configs', nargs='+') | |
args = parser.parse_args() | |
for fname in args.configs: | |
name = os.path.splitext(fname)[0] | |
cfg = ConfigParser() | |
cfg.read(fname) | |
gen_from_cfg(name, cfg) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment