CLOUDSTACK-10013: Fix ipsec VPN configuration

- Fixes strongswan/ipsec, l2tpd and pppd configs
- Uses auto=route in ipsec configs
- Fixes road-warrior setup
- Fixes site-to-site VPN with automatic connection configuration
- Fixes vpc_vpn tests

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2017-12-01 20:58:18 +05:30
parent 9aa7d4e818
commit 8c53574c91
7 changed files with 55 additions and 53 deletions

View File

@ -546,10 +546,6 @@ class CsSite2SiteVpn(CsDataBag):
ikepolicy=obj['ike_policy'].replace(';','-')
esppolicy=obj['esp_policy'].replace(';','-')
pfs='no'
if 'modp' in esppolicy:
pfs='yes'
if rightpeer in self.confips:
self.confips.remove(rightpeer)
file = CsFile(vpnconffile)
@ -557,7 +553,6 @@ class CsSite2SiteVpn(CsDataBag):
file.search("conn ", "conn vpn-%s" % rightpeer)
file.addeq(" left=%s" % leftpeer)
file.addeq(" leftsubnet=%s" % obj['local_guest_cidr'])
file.addeq(" leftnexthop=%s" % obj['local_public_gateway'])
file.addeq(" right=%s" % rightpeer)
file.addeq(" rightsubnet=%s" % peerlist)
file.addeq(" type=tunnel")
@ -567,9 +562,8 @@ class CsSite2SiteVpn(CsDataBag):
file.addeq(" ikelifetime=%s" % self.convert_sec_to_h(obj['ike_lifetime']))
file.addeq(" esp=%s" % esppolicy)
file.addeq(" lifetime=%s" % self.convert_sec_to_h(obj['esp_lifetime']))
file.addeq(" pfs=%s" % pfs)
file.addeq(" keyingtries=2")
file.addeq(" auto=start")
file.addeq(" auto=route")
if 'encap' not in obj:
obj['encap']=False
file.addeq(" forceencaps=%s" % CsHelper.bool_to_yn(obj['encap']))
@ -585,10 +579,20 @@ class CsSite2SiteVpn(CsDataBag):
logging.info("Configured vpn %s %s", leftpeer, rightpeer)
CsHelper.execute("ipsec rereadsecrets")
# This will load the new config and start the connection when needed since auto=start in the config
# This will load the new config
CsHelper.execute("ipsec reload")
os.chmod(vpnsecretsfile, 0400)
for i in xrange(3):
result = CsHelper.execute('ipsec status vpn-%s | grep "%s"' % (rightpeer, peerlist.split(",", 1)[0]))
if len(result) > 0:
break
time.sleep(1)
# With 'auto=route', connections are established on an attempt to
# communicate over the S2S VPN. This uses ping to initialize the connection.
CsHelper.execute("timeout 5 ping -c 3 %s" % (peerlist.split("/", 1)[0].replace(".0", ".1")))
def convert_sec_to_h(self, val):
hrs = int(val) / 3600
return "%sh" % hrs
@ -658,6 +662,7 @@ class CsRemoteAccessVpn(CsDataBag):
self.confips = []
logging.debug(self.dbag)
for public_ip in self.dbag:
if public_ip == "id":
continue
@ -665,12 +670,13 @@ class CsRemoteAccessVpn(CsDataBag):
#Enable remote access vpn
if vpnconfig['create']:
shutdownIpsec = False
logging.debug("Enabling remote access vpn on "+ public_ip)
dev = CsHelper.get_device(public_ip)
if dev == "":
logging.error("Request for ipsec to %s not possible because ip is not configured", public_ip)
continue
logging.error("Request for ipsec to %s not possible because ip is not configured", public_ip)
continue
CsHelper.start_if_stopped("ipsec")
self.configure_l2tpIpsec(public_ip, self.dbag[public_ip])
@ -682,7 +688,6 @@ class CsRemoteAccessVpn(CsDataBag):
CsHelper.execute("ipsec rereadsecrets")
else:
logging.debug("Disabling remote access vpn .....")
#disable remote access vpn
CsHelper.execute("ipsec down L2TP-PSK")
CsHelper.execute("systemctl stop xl2tpd")
@ -693,7 +698,6 @@ class CsRemoteAccessVpn(CsDataBag):
xl2tpdconffile="/etc/xl2tpd/xl2tpd.conf"
xl2tpoptionsfile='/etc/ppp/options.xl2tpd'
file = CsFile(l2tpconffile)
localip=obj['local_ip']
localcidr=obj['local_cidr']
publicIface=obj['public_interface']
@ -701,13 +705,13 @@ class CsRemoteAccessVpn(CsDataBag):
psk=obj['preshared_key']
#left
file.addeq(" left=%s" % left)
file.commit()
l2tpfile = CsFile(l2tpconffile)
l2tpfile.addeq(" left=%s" % left)
l2tpfile.commit()
secret = CsFile(vpnsecretfilte)
secret.empty()
secret.addeq(": PSK \"%s\"" %psk)
secret.addeq("%s %%any : PSK \"%s\"" % (left, psk))
secret.commit()
xl2tpdconf = CsFile(xl2tpdconffile)
@ -730,6 +734,8 @@ class CsRemoteAccessVpn(CsDataBag):
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])
self.fw.append(["", "", "-A OUTPUT -p ah -j ACCEPT"])
self.fw.append(["", "", "-A OUTPUT -p esp -j ACCEPT"])
if self.config.is_vpc():
self.fw.append(["", ""," -N VPN_FORWARD"])

View File

@ -142,7 +142,6 @@ ipsec_tunnel_add() {
sudo echo "conn vpn-$rightpeer" > $vpnconffile &&
sudo echo " left=$leftpeer" >> $vpnconffile &&
sudo echo " leftsubnet=$leftnet" >> $vpnconffile &&
sudo echo " leftnexthop=$leftnexthop" >> $vpnconffile &&
sudo echo " right=$rightpeer" >> $vpnconffile &&
sudo echo " rightsubnets={$rightnets}" >> $vpnconffile &&
sudo echo " type=tunnel" >> $vpnconffile &&
@ -152,9 +151,8 @@ ipsec_tunnel_add() {
sudo echo " ikelifetime=${ikelifetime}s" >> $vpnconffile &&
sudo echo " esp=$esppolicy" >> $vpnconffile &&
sudo echo " salifetime=${esplifetime}s" >> $vpnconffile &&
sudo echo " pfs=$pfs" >> $vpnconffile &&
sudo echo " keyingtries=2" >> $vpnconffile &&
sudo echo " auto=start" >> $vpnconffile &&
sudo echo " auto=route" >> $vpnconffile &&
sudo echo "$leftpeer $rightpeer: PSK \"$secret\"" > $vpnsecretsfile &&
sudo chmod 0400 $vpnsecretsfile
@ -291,12 +289,6 @@ do
done < /tmp/iflist
rightnets=${rightnets//,/ }
pfs="no"
echo "$esppolicy" | grep "modp" > /dev/null
if [ $? -eq 0 ]
then
pfs="yes"
fi
ret=0
#Firewall ports for one-to-one/static NAT

View File

@ -50,8 +50,6 @@ echo $processname >> $configFile
echo $service_name >> $configFile
echo $pidfile >> $configFile
done
}

View File

@ -1,13 +1,9 @@
#ipsec remote access vpn configuration
conn L2TP-PSK
authby=psk
pfs=no
authby=secret
rekey=no
keyingtries=3
keyexchange=ikev1
forceencaps=yes
leftfirewall=yes
leftnexthop=%defaultroute
type=transport
#
# ----------------------------------------------------------
@ -19,7 +15,7 @@ conn L2TP-PSK
#
left=172.26.0.151
#
leftprotoport=17/1701
leftprotoport=udp/l2tp
# If you insist on supporting non-updated Windows clients,
# you can use: leftprotoport=17/%any
#
@ -31,10 +27,10 @@ conn L2TP-PSK
# If you want to allow multiple connections from any IP address,
# you can use: right=%any
#
rightprotoport=17/%any
rightprotoport=udp/%any
#
# ----------------------------------------------------------
# Change 'ignore' to 'add' to enable this configuration.
#
rightsubnetwithin=0.0.0.0/0
auto=add
auto=route

View File

@ -4,11 +4,9 @@ ipcp-accept-remote
noccp
idle 1800
auth
crtscts
mtu 1410
mru 1410
nodefaultroute
debug
lock
connect-delay 5000
ms-dns 10.1.1.1

View File

@ -87,15 +87,15 @@ iptables_() {
}
start_ipsec() {
service ipsec status > /dev/null
systemctl is-active ipsec > /dev/null
if [ $? -ne 0 ]
then
service ipsec start > /dev/null
systemctl start ipsec > /dev/null
#Wait until ipsec started, 5 seconds at most
for i in {1..5}
do
logger -t cloud "$(basename $0): waiting ipsec start..."
service ipsec status > /dev/null
systemctl is-active ipsec > /dev/null
result=$?
if [ $result -eq 0 ]
then
@ -104,7 +104,7 @@ start_ipsec() {
sleep 1
done
fi
service ipsec status > /dev/null
systemctl is-active ipsec > /dev/null
return $?
}
@ -112,14 +112,14 @@ ipsec_server() {
local op=$1
case $op in
"start") start_ipsec
sudo service xl2tpd start
sudo systemctl start xl2tpd
;;
"stop") sudo service xl2tpd stop
"stop") sudo systemctl stop xl2tpd
;;
"restart") start_ipsec
sudo ipsec auto --rereadall
service xl2tpd stop
service xl2tpd start
systemctl stop xl2tpd
systemctl start xl2tpd
;;
esac
}
@ -131,7 +131,7 @@ create_l2tp_ipsec_vpn_server() {
local local_ip=$4
sed -i -e "s/left=.*$/left=$public_ip/" /etc/ipsec.d/l2tp.conf
echo ": PSK \"$ipsec_psk\"" > /etc/ipsec.d/ipsec.any.secrets
echo "$public_ip %any : PSK \"$ipsec_psk\"" > /etc/ipsec.d/ipsec.any.secrets
sed -i -e "s/^ip range = .*$/ip range = $client_range/" /etc/xl2tpd/xl2tpd.conf
sed -i -e "s/^local ip = .*$/local ip = $local_ip/" /etc/xl2tpd/xl2tpd.conf

View File

@ -21,7 +21,8 @@ from marvin.codes import PASS, FAILED
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.utils import (validateList,
cleanup_resources,
get_process_status)
get_process_status,
wait_until)
from marvin.lib.base import (Domain,
Account,
@ -184,7 +185,7 @@ class Services:
},
"vpn": {
"vpn_user": "root",
"vpn_pass": "Md1s#dc",
"vpn_pass": "Md1sdc",
"vpn_pass_fail": "abc!123", # too short
"iprange": "10.3.2.1-10.3.2.10",
"fordisplay": "true"
@ -757,8 +758,19 @@ class TestVpcSite2SiteVpn(cloudstackTestCase):
self.apiclient, customer2_response.id, vpn1_response['id'])
self.debug("VPN connection created for VPC %s" % vpc1.id)
self.assertEqual(
vpnconn2_response['state'], "Connected", "Failed to connect between VPCs!")
def checkVpnConnected():
connections = Vpn.listVpnConnection(
self.apiclient,
listall='true',
vpcid=vpc2.id)
if isinstance(connections, list):
return connections[0].state == 'Connected', None
return False, None
# Wait up to 60 seconds for passive connection to show up as Connected
res, _ = wait_until(2, 30, checkVpnConnected)
if not res:
self.fail("Failed to connect between VPCs, see VPN state as Connected")
# acquire an extra ip address to use to ssh into vm2
try:
@ -793,9 +805,9 @@ class TestVpcSite2SiteVpn(cloudstackTestCase):
if ssh_client:
# run ping test
packet_loss = ssh_client.execute(
"/bin/ping -c 3 -t 10 " + vm1.nic[0].ipaddress + " |grep packet|cut -d ' ' -f 7| cut -f1 -d'%'")[0]
self.assert_(int(packet_loss) == 0, "Ping did not succeed")
packet_loss = ssh_client.execute("/bin/ping -c 3 -t 10 " + vm1.nic[0].ipaddress + " | grep packet | sed 's/.*received, //g' | sed 's/[% ]*packet.*//g'")[0]
# during startup, some packets may not reply due to link/ipsec-route setup
self.assert_(int(packet_loss) < 50, "Ping did not succeed")
else:
self.fail("Failed to setup ssh connection to %s" % vm2.public_ip)