Skip to content

Instantly share code, notes, and snippets.

@wnn
Last active May 19, 2017 10:29
Show Gist options
  • Save wnn/74d98041c4630f273680 to your computer and use it in GitHub Desktop.
Save wnn/74d98041c4630f273680 to your computer and use it in GitHub Desktop.
#! /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