279 lines
12 KiB
Python
279 lines
12 KiB
Python
# Copyright 2014 OpenStack Foundation
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed 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.
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import urllib2
|
|
|
|
from lxml import etree
|
|
from oslo_log import log
|
|
import paramiko
|
|
from tempest.lib.common import ssh
|
|
from tempest.lib.common.utils import data_utils
|
|
from tempest.lib import decorators
|
|
import testtools
|
|
|
|
from ec2api.tests.functional import base
|
|
from ec2api.tests.functional import config
|
|
from ec2api.tests.functional.scenario import base as scenario_base
|
|
|
|
CONF = config.CONF
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
class VpnTest(scenario_base.BaseScenarioTest):
|
|
|
|
CUSTOMER_GATEWAY_IP = '198.51.100.77'
|
|
CUSTOMER_VPN_CIDR = '172.16.25.0/24'
|
|
OPENSWAN_LINK = ('http://mirrors.kernel.org/ubuntu/pool/universe/o/'
|
|
'openswan/openswan_2.6.38-1_i386.deb')
|
|
|
|
@classmethod
|
|
@base.safe_setup
|
|
def setUpClass(cls):
|
|
super(VpnTest, cls).setUpClass()
|
|
if not base.TesterStateHolder().get_vpc_enabled():
|
|
raise cls.skipException('VPC is disabled')
|
|
base.check_network_feature_enabled('vpnaas')
|
|
|
|
@decorators.idempotent_id('63c2ac38-cfee-45d3-b765-c9b43859660d')
|
|
def test_vpn_routing(self):
|
|
vpc_id, _subnet_id = self.create_vpc_and_subnet('10.42.0.0/20')
|
|
|
|
vpn_data = self._create_and_configure_vpn(
|
|
vpc_id, self.CUSTOMER_GATEWAY_IP, self.CUSTOMER_VPN_CIDR)
|
|
vgw_id = vpn_data['VpnGatewayId']
|
|
|
|
data = self.client.describe_route_tables(
|
|
Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])
|
|
rtb_id = data['RouteTables'][0]['RouteTableId']
|
|
data = self.client.describe_route_tables(RouteTableIds=[rtb_id])
|
|
data = data['RouteTables'][0]
|
|
route = next((r for r in data['Routes']
|
|
if r['DestinationCidrBlock'] == self.CUSTOMER_VPN_CIDR),
|
|
None)
|
|
if route:
|
|
self.assertEqual('active', route['State'])
|
|
self.assertEqual('EnableVgwRoutePropagation', route['Origin'])
|
|
self.assertIn('PropagatingVgws', data)
|
|
self.assertNotEmpty(data['PropagatingVgws'])
|
|
self.assertEqual(vgw_id, data['PropagatingVgws'][0]['GatewayId'])
|
|
|
|
@decorators.idempotent_id('9e284d9e-8fee-43c7-bcfb-8ed0dfa27dbc')
|
|
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
|
|
@testtools.skipUnless(CONF.aws.run_long_tests, 'Slow test has skipped.')
|
|
@testtools.skipUnless(CONF.aws.image_id_ubuntu,
|
|
"ubuntu image id is not defined")
|
|
@testtools.skipUnless(CONF.aws.image_id,
|
|
"image id is not defined")
|
|
def test_vpn_connectivity(self):
|
|
is_amazon = 'amazon' in CONF.aws.ec2_url
|
|
|
|
response = urllib2.urlopen(self.OPENSWAN_LINK, timeout=30)
|
|
content = response.read()
|
|
if not is_amazon:
|
|
# NOTE(andrey-mp): gating in openstack doesn't have internet access
|
|
# so we need to download this package and install it with dpkg
|
|
filename = os.path.basename(self.OPENSWAN_LINK)
|
|
f = open(filename, 'w')
|
|
f.write(content)
|
|
f.close()
|
|
|
|
key_name = data_utils.rand_name('testkey')
|
|
pkey = self.create_key_pair(key_name)
|
|
|
|
# run ubuntu instance to create one of VPN endpoint inside
|
|
sec_group_name = self.create_standard_security_group()
|
|
instance_id_ubuntu = self.run_instance(
|
|
KeyName=key_name, ImageId=CONF.aws.image_id_ubuntu,
|
|
SecurityGroups=[sec_group_name])
|
|
public_ip_ubuntu = self.get_instance_ip(instance_id_ubuntu)
|
|
instance = self.get_instance(instance_id_ubuntu)
|
|
private_ip_ubuntu = instance['PrivateIpAddress']
|
|
|
|
# create VPC, ..., VPN
|
|
vpc_id, subnet_id = self.create_vpc_and_subnet('10.43.0.0/20')
|
|
self.prepare_vpc_default_security_group(vpc_id)
|
|
vpn_data = self._create_and_configure_vpn(
|
|
vpc_id, public_ip_ubuntu, private_ip_ubuntu + '/32')
|
|
|
|
# run general instance inside VPC
|
|
instance_id = self.run_instance(KeyName=key_name,
|
|
ImageId=CONF.aws.image_id,
|
|
SubnetId=subnet_id)
|
|
instance = self.get_instance(instance_id)
|
|
private_ip_in_vpc = instance['PrivateIpAddress']
|
|
|
|
# configure ubuntu, install openswan and run it
|
|
ssh_client = ssh.Client(public_ip_ubuntu, CONF.aws.image_user_ubuntu,
|
|
pkey=pkey)
|
|
if not is_amazon:
|
|
self._upload_file(ssh_client, filename, filename)
|
|
ssh_client.exec_command('sudo DEBIAN_FRONTEND=noninteractive'
|
|
' dpkg -i ' + filename)
|
|
else:
|
|
ssh_client.exec_command('DEBIAN_FRONTEND=noninteractive sudo '
|
|
'apt-get install -fqy openswan')
|
|
ssh_client.exec_command('sudo -s su -c "'
|
|
'echo 1 > /proc/sys/net/ipv4/ip_forward"')
|
|
ssh_client.exec_command(
|
|
'for vpn in /proc/sys/net/ipv4/conf/*; do sudo -s su -c'
|
|
' "echo 0 > $vpn/accept_redirects; echo 0 > $vpn/send_redirects";'
|
|
' done')
|
|
sysctl_additions = [
|
|
'net.ipv4.ip_forward = 1',
|
|
'net.ipv4.conf.all.accept_redirects = 0',
|
|
'net.ipv4.conf.all.send_redirects = 0']
|
|
for item in sysctl_additions:
|
|
ssh_client.exec_command(
|
|
'sudo -s su -c "echo \'' + item + '\' >> /etc/sysctl.conf"')
|
|
ssh_client.exec_command('sudo sysctl -p')
|
|
ipsec_conf, ipsec_secrets = self._get_ipsec_conf(
|
|
vpn_data['VpnConnectionId'], private_ip_ubuntu)
|
|
ssh_client.exec_command('sudo -s su -c "echo \'\' > /etc/ipsec.conf"')
|
|
for fstr in ipsec_conf:
|
|
ssh_client.exec_command(
|
|
'sudo -s su -c "echo \'%s\' >> /etc/ipsec.conf"' % fstr)
|
|
ssh_client.exec_command(
|
|
'sudo -s su -c "echo \'%s\' > /etc/ipsec.secrets"' % ipsec_secrets)
|
|
|
|
ssh_client.exec_command('sudo service ipsec restart')
|
|
|
|
try:
|
|
self.get_vpn_connection_tunnel_waiter().wait_available(
|
|
vpn_data['VpnConnectionId'], ('UP'))
|
|
except Exception:
|
|
exc_info = sys.exc_info()
|
|
try:
|
|
output = ssh_client.exec_command('sudo ipsec auto --status')
|
|
LOG.warning(output)
|
|
except Exception:
|
|
pass
|
|
raise exc_info[1], None, exc_info[2]
|
|
time.sleep(10)
|
|
|
|
ssh_client.exec_command('ping -c 4 %s' % private_ip_in_vpc)
|
|
|
|
def _upload_file(self, ssh_client, local_path, remote_path):
|
|
ssh = ssh_client._get_ssh_connection()
|
|
transport = ssh.get_transport()
|
|
sftp_client = paramiko.SFTPClient.from_transport(transport)
|
|
sftp_client.put(local_path, remote_path)
|
|
|
|
def _create_and_configure_vpn(self, vpc_id, cgw_ip, customer_subnet):
|
|
data = self.client.create_customer_gateway(
|
|
Type='ipsec.1', PublicIp=cgw_ip, BgpAsn=65000)
|
|
cgw_id = data['CustomerGateway']['CustomerGatewayId']
|
|
self.addResourceCleanUp(
|
|
self.client.delete_customer_gateway, CustomerGatewayId=cgw_id)
|
|
self.get_customer_gateway_waiter().wait_available(cgw_id)
|
|
|
|
data = self.client.create_vpn_gateway(
|
|
Type='ipsec.1', AvailabilityZone=CONF.aws.aws_zone)
|
|
vgw_id = data['VpnGateway']['VpnGatewayId']
|
|
self.addResourceCleanUp(
|
|
self.client.delete_vpn_gateway, VpnGatewayId=vgw_id)
|
|
self.get_vpn_gateway_waiter().wait_available(vgw_id)
|
|
|
|
data = self.client.attach_vpn_gateway(VpnGatewayId=vgw_id,
|
|
VpcId=vpc_id)
|
|
self.addResourceCleanUp(self.client.detach_vpn_gateway,
|
|
VpnGatewayId=vgw_id, VpcId=vpc_id)
|
|
self.get_vpn_gateway_attachment_waiter().wait_available(
|
|
vgw_id, 'attached')
|
|
|
|
data = self.client.describe_route_tables(
|
|
Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])
|
|
rtb_id = data['RouteTables'][0]['RouteTableId']
|
|
data = self.client.enable_vgw_route_propagation(RouteTableId=rtb_id,
|
|
GatewayId=vgw_id)
|
|
self.addResourceCleanUp(self.client.disable_vgw_route_propagation,
|
|
RouteTableId=rtb_id, GatewayId=vgw_id)
|
|
|
|
data = self.client.create_vpn_connection(
|
|
CustomerGatewayId=cgw_id, VpnGatewayId=vgw_id,
|
|
Options={'StaticRoutesOnly': True}, Type='ipsec.1')
|
|
vpn_data = data['VpnConnection']
|
|
vpn_id = data['VpnConnection']['VpnConnectionId']
|
|
self.addResourceCleanUp(self.client.delete_vpn_connection,
|
|
VpnConnectionId=vpn_id)
|
|
self.get_vpn_connection_waiter().wait_available(vpn_id)
|
|
|
|
data = self.client.create_vpn_connection_route(
|
|
VpnConnectionId=vpn_id,
|
|
DestinationCidrBlock=customer_subnet)
|
|
self.get_vpn_connection_route_waiter(customer_subnet).wait_available(
|
|
vpn_id)
|
|
|
|
return vpn_data
|
|
|
|
def _get_ipsec_conf(self, vpn_connection_id, private_ip_ubuntu):
|
|
data = self.client.describe_vpn_connections(
|
|
VpnConnectionIds=[vpn_connection_id])
|
|
vpn_data = data['VpnConnections'][0]
|
|
vpn_config = etree.fromstring(
|
|
vpn_data['CustomerGatewayConfiguration'])
|
|
psks = vpn_config.xpath(
|
|
'/vpn_connection/ipsec_tunnel/ike/pre_shared_key')
|
|
self.assertNotEmpty(psks)
|
|
vgw_ip = vpn_config.xpath(
|
|
'/vpn_connection/ipsec_tunnel/vpn_gateway/tunnel_outside_address'
|
|
'/ip_address')
|
|
self.assertTrue(vgw_ip)
|
|
|
|
ipsec_key = psks[0].text
|
|
vgw_ip = vgw_ip[0].text
|
|
|
|
ipsec_conf = []
|
|
for item in self._ipsec_conf:
|
|
ipsec_conf.append(item % {
|
|
'vpc_cidr': '10.43.0.0/20',
|
|
'vgw_ip': vgw_ip,
|
|
'private_ip_ubuntu': private_ip_ubuntu})
|
|
|
|
ipsec_secrets = ('%(private_ip_ubuntu)s %(vgw_ip)s: '
|
|
'PSK \\"%(ipsec_key)s\\"' % {
|
|
'private_ip_ubuntu': private_ip_ubuntu,
|
|
'vgw_ip': vgw_ip,
|
|
'ipsec_key': ipsec_key})
|
|
|
|
return ipsec_conf, ipsec_secrets
|
|
|
|
_ipsec_conf = [
|
|
'## general configuration parameters ##',
|
|
'config setup',
|
|
' plutodebug=all',
|
|
' plutostderrlog=/var/log/pluto.log',
|
|
' protostack=netkey',
|
|
' nat_traversal=yes',
|
|
' virtual_private=%%v4:%(vpc_cidr)s',
|
|
' nhelpers=0',
|
|
'## connection definition in Debian ##',
|
|
'conn my-conn',
|
|
' authby=secret',
|
|
' auto=start',
|
|
' pfs=yes',
|
|
' type=tunnel',
|
|
' #left side (myside)',
|
|
' left=%(private_ip_ubuntu)s',
|
|
' leftsubnet=%(private_ip_ubuntu)s/32',
|
|
' leftnexthop=%(vgw_ip)s',
|
|
' leftsourceip=%(private_ip_ubuntu)s',
|
|
' #right security gateway (VPN side)',
|
|
' right=%(vgw_ip)s',
|
|
' rightsubnet=%(vpc_cidr)s',
|
|
' rightnexthop=%(private_ip_ubuntu)s']
|