ec2api-tempest-plugin/ec2api_tempest_plugin/scenario/test_vpn.py

280 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 six
from six.moves.urllib.request import urlopen
import sys
import time
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_tempest_plugin import base
from ec2api_tempest_plugin import config
from ec2api_tempest_plugin.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 = 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, 'wb')
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
six.reraise(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']