CLOUDSTACK-8690:Added remote access vpn and vpn users configuration

This commit is contained in:
Jayapal 2015-09-02 11:45:53 +05:30 committed by Jayapal
parent 76c81a7bd9
commit f661ac0a2a
7 changed files with 294 additions and 6 deletions

View File

@ -28,6 +28,7 @@ import re
import time
import shutil
import os.path
import os
from fcntl import flock, LOCK_EX, LOCK_UN
from cs.CsDatabag import CsDataBag, CsCmdLine
@ -484,6 +485,170 @@ class CsSite2SiteVpn(CsDataBag):
hrs = int(val) / 3600
return "%sh" % hrs
class CsVpnUser(CsDataBag):
PPP_CHAP='/etc/ppp/chap-secrets'
def process(self):
for user in self.dbag:
if user == 'id':
continue
userconfig=self.dbag[user]
if userconfig['add']:
self.add_l2tp_ipsec_user(user, userconfig)
else:
self.del_l2tp_ipsec_user(user, userconfig)
def add_l2tp_ipsec_user(self, user, obj):
userfound = False
password = obj['password']
userSearchEntry = "%s \* %s \*"%(user,password)
userAddEntry = "%s * %s *" %(user,password)
logging.debug("Adding vpn user %s" %userSearchEntry)
file = CsFile(self.PPP_CHAP)
userfound = file.searchString(userSearchEntry, '#')
if not userfound:
logging.debug("User is not there already, so adding user ")
self.del_l2tp_ipsec_user(user, obj)
file.add(userAddEntry)
file.commit()
def del_l2tp_ipsec_user(self, user, obj):
userfound = False
password = obj['password']
userentry = "%s \* %s \*"%(user,password)
logging.debug("Deleting the user %s " % user)
file = CsFile(self.PPP_CHAP)
file.deleteLine(userentry)
file.commit()
if not os.path.exists('/var/run/pppd2.tdb'):
return
logging.debug("kiing the PPPD process for the user %s " % user)
fileContents = CsHelper.execute("tdbdump /var/run/pppd2.tdb")
print fileContents
for line in fileContents:
if user in line:
contentlist = line.split(';')
for str in contentlist:
print 'in del_l2tp str = '+ str
pppd = str.split('=')[0]
if pppd == 'PPPD_PID':
pid = str.split('=')[1]
if pid:
logging.debug("killing process %s" %pid)
CsHelper.execute('kill -9 %s' % pid)
class CsRemoteAccessVpn(CsDataBag):
VPNCONFDIR = "/etc/ipsec.d"
def process(self):
self.confips = []
logging.debug(self.dbag)
for public_ip in self.dbag:
if public_ip == "id":
continue
vpnconfig=self.dbag[public_ip]
#Enable remote access vpn
if vpnconfig['create']:
logging.debug("Enabling remote access vpn on "+ public_ip)
self.configure_l2tpIpsec(public_ip, self.dbag[public_ip])
logging.debug("Remote accessvpn data bag %s", self.dbag)
self.remoteaccessvpn_iptables(public_ip, self.dbag[public_ip])
CsHelper.execute("ipsec auto --rereadall")
CsHelper.execute("service xl2tpd stop")
CsHelper.execute("service xl2tpd start")
CsHelper.execute("ipsec auto --rereadsecrets")
CsHelper.execute("ipsec auto --replace L2TP-PSK")
else:
logging.debug("Disabling remote access vpn .....")
#disable remote access vpn
CsHelper.execute("ipsec auto --down L2TP-PSK")
CsHelper.execute("service xl2tpd stop")
def configure_l2tpIpsec(self, left, obj):
vpnconffile="%s/l2tp.conf" % (self.VPNCONFDIR)
vpnsecretfilte="%s/ipsec.any.secrets" % (self.VPNCONFDIR)
xl2tpdconffile="/etc/xl2tpd/xl2tpd.conf"
xl2tpoptionsfile='/etc/ppp/options.xl2tpd'
file = CsFile(vpnconffile)
localip=obj['local_ip']
localcidr=obj['local_cidr']
publicIface=obj['public_interface']
iprange=obj['ip_range']
psk=obj['preshared_key']
#left
file.addeq(" left=%s" % left)
file.commit()
secret = CsFile(vpnsecretfilte)
secret.addeq(": PSK \"%s\"" %psk)
secret.commit()
xl2tpdconf = CsFile(xl2tpdconffile)
xl2tpdconf.addeq("ip range = %s" %iprange)
xl2tpdconf.addeq("local ip = %s" %localip)
xl2tpdconf.commit()
xl2tpoptions=CsFile(xl2tpoptionsfile)
xl2tpoptions.search("ms-dns ", "ms-dns %s" %localip)
xl2tpoptions.commit()
def remoteaccessvpn_iptables(self, publicip, obj):
publicdev=obj['public_interface']
localcidr=obj['local_cidr']
local_ip=obj['local_ip']
self.fw.append(["", "", "-A INPUT -i %s --dst %s -p udp -m udp --dport 500 -j ACCEPT" % (publicdev, publicip)])
self.fw.append(["", "", "-A INPUT -i %s --dst %s -p udp -m udp --dport 4500 -j ACCEPT" % (publicdev, publicip)])
self.fw.append(["", "", "-A INPUT -i %s --dst %s -p udp -m udp --dport 1701 -j ACCEPT" % (publicdev, publicip)])
self.fw.append(["", "", "-A INPUT -i %s -p ah -j ACCEPT" % publicdev])
self.fw.append(["", "", "-A INPUT -i %s -p esp -j ACCEPT" % publicdev])
if self.config.is_vpc():
self.fw.append(["", ""," -N VPN_FORWARD"])
self.fw.append(["", "","-I FORWARD -i ppp+ -j VPN_FORWARD"])
self.fw.append(["", "","-I FORWARD -o ppp+ -j VPN_FORWARD"])
self.fw.append(["", "","-I FORWARD -o ppp+ -j VPN_FORWARD"])
self.fw.append(["", "","-A VPN_FORWARD -s %s -j RETURN" %localcidr])
self.fw.append(["", "","-A VPN_FORWARD -i ppp+ -d %s -j RETURN" %localcidr])
self.fw.append(["", "","-A VPN_FORWARD -i ppp+ -o ppp+ -j RETURN"])
else:
self.fw.append(["", "","-A FORWARD -i ppp+ -o ppp+ -j ACCEPT"])
self.fw.append(["", "","-A FORWARD -s %s -o ppp+ -j ACCEPT" % localcidr])
self.fw.append(["", "","-A FORWARD -i ppp+ -d %s -j ACCEPT" % localcidr])
self.fw.append(["", "","-A INPUT -i ppp+ -m udp -p udp --dport 53 -j ACCEPT"])
self.fw.append(["", "","-A INPUT -i ppp+ -m tcp -p tcp --dport 53 -j ACCEPT"])
self.fw.append(["nat", "","-I PREROUTING -i ppp+ -m tcp --dport 53 -j DNAT --to-destination %s" % local_ip])
if self.config.is_vpc():
return
self.fw.append(["mangle", "","-N VPN_%s " %publicip])
self.fw.append(["mangle", "","-I PREROUTING -d %s -j VPN_%s " % (publicip, publicip)])
self.fw.append(["mangle", "","-A VPN_%s -p ah -j ACCEPT " % publicip])
self.fw.append(["mangle", "","-A VPN_%s -p esp -j ACCEPT " % publicip])
self.fw.append(["mangle", "","-A VPN_%s -j RETURN " % publicip])
class CsForwardingRules(CsDataBag):
@ -672,15 +837,20 @@ def main(argv):
fwd = CsForwardingRules("forwardingrules", config)
fwd.process()
nf = CsNetfilters()
nf.compare(config.get_fw())
red = CsRedundant(config)
red.set()
vpns = CsSite2SiteVpn("site2sitevpn", config)
vpns.process()
#remote access vpn
rvpn = CsRemoteAccessVpn("remoteaccessvpn", config)
rvpn.process()
#remote access vpn users
vpnuser = CsVpnUser("vpnuserlist", config)
vpnuser.process()
dhcp = CsDhcp("dhcpentry", config)
dhcp.process()

View File

@ -130,5 +130,34 @@ class CsFile:
return True
return False
def searchString(self, search, ignoreLinesStartWith):
found = False
logging.debug("Searching for %s string " % search)
for index, line in enumerate(self.new_config):
print ' line = ' +line
if line.lstrip().startswith(ignoreLinesStartWith):
continue
if re.search(search, line):
found = True
break
return found
def deleteLine(self, search):
found = False
logging.debug("Searching for %s to remove the line " % search)
temp_config = []
for index, line in enumerate(self.new_config):
if line.lstrip().startswith("#"):
continue
if not re.search(search, line):
temp_config.append(line)
self.new_config = list(temp_config)
def compare(self, o):
return (isinstance(o, self.__class__) and set(self.config) == set(o.new_config))

View File

@ -157,7 +157,7 @@ def get_hostname():
def execute(command):
""" Execute command """
logging.debug("Executing %s" % command)
logging.debug("Executing: %s" % command)
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
result = p.communicate()[0]
return result.splitlines()
@ -178,7 +178,7 @@ def save_iptables(command, iptables_file):
def execute2(command):
""" Execute command """
logging.debug("Executing %s" % command)
logging.debug("Executing: %s" % command)
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
p.wait()
return p

View File

@ -0,0 +1,28 @@
# -- coding: utf-8 --
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from pprint import pprint
def merge(dbag, vpn):
key = vpn['vpn_server_ip']
op = vpn['create']
if key in dbag.keys() and not op:
del(dbag[key])
else:
dbag[key] = vpn
return dbag

View File

@ -0,0 +1,48 @@
# -- coding: utf-8 --
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from pprint import pprint
import copy
def merge(dbag, data):
dbagc = copy.deepcopy(dbag)
print dbag
print data
if "vpn_users" not in data:
return dbagc
# remove previously deleted user from the dict
for user in dbagc.keys():
if user == 'id':
continue
userrec = dbagc[user]
add = userrec['add']
if not add:
del(dbagc[user])
for user in data['vpn_users']:
username=user['user']
add=user['add']
if username not in dbagc.keys():
dbagc[username] = user
elif username in dbagc.keys() and not add:
dbagc[username] = user
return dbagc

View File

@ -32,6 +32,8 @@ import cs_vmdata
import cs_dhcp
import cs_forwardingrules
import cs_site2sitevpn
import cs_remoteaccessvpn
import cs_vpnusers
from pprint import pprint
@ -66,6 +68,7 @@ class DataBag:
logging.error("Could not write data bag %s", self.key)
else:
logging.debug("Writing data bag type %s", self.key)
logging.debug(dbag)
jsono = json.dumps(dbag, indent=4, sort_keys=True)
handle.write(jsono)
@ -119,6 +122,10 @@ class updateDataBag:
dbag = self.processForwardingRules(self.db.getDataBag())
elif self.qFile.type == 'site2sitevpn':
dbag = self.process_site2sitevpn(self.db.getDataBag())
elif self.qFile.type == 'remoteaccessvpn':
dbag = self.process_remoteaccessvpn(self.db.getDataBag())
elif self.qFile.type == 'vpnuserlist':
dbag = self.process_vpnusers(self.db.getDataBag())
else:
logging.error("Error I do not know what to do with file of type %s", self.qFile.type)
return
@ -147,6 +154,12 @@ class updateDataBag:
def process_site2sitevpn(self, dbag):
return cs_site2sitevpn.merge(dbag, self.qFile.data)
def process_remoteaccessvpn(self, dbag):
return cs_remoteaccessvpn.merge(dbag, self.qFile.data)
def process_vpnusers(self, dbag):
return cs_vpnusers.merge(dbag, self.qFile.data)
def process_network_acl(self, dbag):
return cs_network_acl.merge(dbag, self.qFile.data)

View File

@ -26,7 +26,7 @@ import os.path
import configure
import json
logging.basicConfig(filename='/var/log/cloud.log', level=logging.DEBUG, format='%(asctime)s %(message)s')
logging.basicConfig(filename='/var/log/cloud.log', level=logging.DEBUG, format='%(asctime)s %(filename)s %(funcName)s:%(lineno)d %(message)s')
# first commandline argument should be the file to process
if (len(sys.argv) != 2):