def _upgrade_skip_check(cls):
        if not Topology.at_nuage(cls._to_release):

            # -- Mind --
            # E.g. take upgrade from 5.4 to 6.0
            # -> The SUT is deployed with 6.0 Nuage (VSD/VSC/VRS) but with
            #    5.4 OpenStack Nuage plugin branch
            # -> The (no-)skip verification is testing for the Nuage version
            #    to be 6.0
            # -> I.e. the OpenStack plugin branch version is not at play in
            #    the check (!)

            msg = ('Upgrade tests to {} are applicable only when the deployed '
                   'Nuage version (i.e. version of VSD/VSC/VRS) is set '
                   'accordingly').format(cls._from_release)
            raise cls.skipException(msg)
예제 #2
0
class TestFWaaS(fwaas_mixins.FWaaSClientMixin, NuageBaseTest):

    default_prepare_for_connectivity = True

    @classmethod
    def skip_checks(cls):
        super(TestFWaaS, cls).skip_checks()
        if not Topology.has_fwaas_v6_support():
            msg = 'No fwaas v6 support.'
            raise cls.skipException(msg)

    def setUp(self):
        super(TestFWaaS, self).setUp()
        required_exts = ['fwaas', 'security-group', 'router']
        for ext in required_exts:
            if not test.is_extension_enabled(ext, 'network'):
                msg = "%s Extension not enabled." % ext
                raise self.skipException(msg)

    def assert_no_icmp_connectivity(self, **kwargs):
        self.assert_icmp_connectivity(is_connectivity_expected=False, **kwargs)

    def assert_no_tcp_connectivity(self, **kwargs):
        self.assert_tcp_connectivity(is_connectivity_expected=False, **kwargs)

    def assert_connectivity(self, **kwargs):
        self.assert_icmp_connectivity(**kwargs)
        self.assert_tcp_connectivity(**kwargs)

    def assert_no_connectivity(self, **kwargs):
        self.assert_no_icmp_connectivity(**kwargs)
        self.assert_no_tcp_connectivity(**kwargs)

    def _empty_policy(self, router_id=None, **_kwargs):
        # NOTE(yamamoto): an empty policy would deny all
        # We allow ipv4 traffic here
        fw_rule_ipv4 = self.create_firewall_rule(action='allow', ip_version=4)
        fw_policy = self.create_firewall_policy(
            firewall_rules=[fw_rule_ipv4['id']])
        fw = self.create_firewall(firewall_policy_id=fw_policy['id'],
                                  router_ids=[router_id])
        self._wait_firewall_ready(fw['id'])
        return {
            'fw': fw,
            'fw_policy': fw_policy,
        }

    def _all_disabled_rules(self, **_kwargs):
        # NOTE(yamamoto): a policy whose rules are all disabled would deny all
        fw_rule = self.create_firewall_rule(action="allow",
                                            enabled=False,
                                            ip_version=6)
        fw_rule_ipv4 = self.create_firewall_rule(action='allow', ip_version=4)
        fw_policy = self.create_firewall_policy(
            firewall_rules=[fw_rule['id'], fw_rule_ipv4['id']])
        fw = self.create_firewall(firewall_policy_id=fw_policy['id'])
        self._wait_firewall_ready(fw['id'])
        return {
            'fw': fw,
            'fw_policy': fw_policy,
            'fw_rule': fw_rule,
        }

    def _block_destination_ip(self, server1_fixed_ip, server2_fixed_ip,
                              router_id, **_kwargs):
        rules = [
            # NOTE(yamamoto): The filtering is taken place after
            # destination ip is rewritten to fixed-ip.
            self.create_firewall_rule(destination_ip_address=server2_fixed_ip,
                                      action="deny",
                                      ip_version=6),
            self.create_firewall_rule(action='allow', ip_version=6),
            self.create_firewall_rule(action="allow", ip_version=4)
        ]
        rule_ids = [r['id'] for r in rules]
        fw_policy = self.create_firewall_policy(firewall_rules=rule_ids)
        fw = self.create_firewall(firewall_policy_id=fw_policy['id'],
                                  router_ids=[router_id])
        self._wait_firewall_ready(fw['id'])
        return {
            'fw': fw,
            'fw_policy': fw_policy,
            'server1_fixed_ip': server1_fixed_ip,
            'server2_fixed_ip': server2_fixed_ip,
        }

    def _block_source_ip(self, server1_fixed_ip, server2_fixed_ip, router_id,
                         **_kwargs):
        rules = [
            # NOTE(yamamoto): The filtering is taken place after
            # destination ip is rewritten to fixed-ip.
            self.create_firewall_rule(source_ip_address=server1_fixed_ip,
                                      action="deny",
                                      ip_version=6),
            self.create_firewall_rule(action='allow', ip_version=6),
            self.create_firewall_rule(action="allow", ip_version=4)
        ]
        fw_policy = self.create_firewall_policy(
            firewall_rules=[r['id'] for r in rules])
        fw = self.create_firewall(firewall_policy_id=fw_policy['id'],
                                  router_ids=[router_id])
        self._wait_firewall_ready(fw['id'])
        return {
            'fw': fw,
            'fw_policy': fw_policy,
            'server1_fixed_ip': server1_fixed_ip,
            'server2_fixed_ip': server2_fixed_ip,
        }

    def _block_icmp(self, router_id=None, **_kwargs):
        deny_icmp = self.create_firewall_rule(protocol="ipv6-icmp",
                                              action="deny",
                                              ip_version=6)
        allow_ipv6 = self.create_firewall_rule(action="allow", ip_version=6)
        allow_ipv4 = self.create_firewall_rule(action='allow', ip_version=4)
        fw_policy = self.create_firewall_policy(firewall_rules=[
            deny_icmp['id'], allow_ipv6['id'], allow_ipv4['id']
        ])

        fw = self.create_firewall(firewall_policy_id=fw_policy['id'],
                                  router_ids=[router_id])
        self._wait_firewall_ready(fw['id'])

        return {
            'fw': fw,
            'fw_policy': fw_policy,
            'fw_rule': deny_icmp,
            'router_id': router_id
        }

    def _block_all_with_default_allow(self, router_id, **_kwargs):
        fw_rule = self.create_firewall_rule(action="deny", ip_version=6)
        fw_rule_allow = self.create_firewall_rule(action="allow", ip_version=6)
        fw_rule_ipv4 = self.create_firewall_rule(action='allow', ip_version=4)
        fw_policy = self.create_firewall_policy(firewall_rules=[
            fw_rule['id'], fw_rule_allow['id'], fw_rule_ipv4['id']
        ])
        fw = self.create_firewall(firewall_policy_id=fw_policy['id'],
                                  router_ids=[router_id])
        self._wait_firewall_ready(fw['id'])
        return {
            'fw': fw,
            'fw_policy': fw_policy,
            'fw_rules': [fw_rule],
        }

    def _block_certain_ports(self, router_id, **_kwargs):
        deny_source_9090 = self.create_firewall_rule(action="deny",
                                                     ip_version=6,
                                                     source_port=9090,
                                                     protocol='tcp')
        deny_destination_80 = self.create_firewall_rule(action="deny",
                                                        ip_version=6,
                                                        destination_port=80,
                                                        protocol='tcp')
        allow_v6 = self.create_firewall_rule(action="allow", ip_version=6)
        allow_v4 = self.create_firewall_rule(action='allow', ip_version=4)

        fw_policy = self.create_firewall_policy(firewall_rules=[
            deny_source_9090['id'], deny_destination_80['id'], allow_v6['id'],
            allow_v4['id']
        ])
        fw = self.create_firewall(firewall_policy_id=fw_policy['id'],
                                  router_ids=[router_id])
        self._wait_firewall_ready(fw['id'])
        return {
            'fw': fw,
            'fw_policy': fw_policy,
            'fw_rules': (deny_source_9090, deny_destination_80),
        }

    def _confirm_certain_ports_blocked(self, from_server, to_server):

        servers = {'from_server': from_server, 'to_server': to_server}

        # icmp not blocked
        self.assert_icmp_connectivity(**servers)

        # ports that are not blocked
        self.assert_tcp_connectivity(destination_port=81,
                                     source_port=9091,
                                     **servers)
        # blocked destination port
        self.assert_no_tcp_connectivity(destination_port=80,
                                        source_port=9092,
                                        **servers)
        # blocked source port
        self.assert_no_tcp_connectivity(destination_port=81,
                                        source_port=9090,
                                        **servers)

    def _confirm_certain_ports_allowed(self, from_server, to_server):

        servers = {'from_server': from_server, 'to_server': to_server}

        # icmp not blocked
        self.assert_icmp_connectivity(**servers)

        # ports that are not blocked
        self.assert_tcp_connectivity(destination_port=81,
                                     source_port=9091,
                                     **servers)

        # blocked destination port
        self.assert_tcp_connectivity(destination_port=80,
                                     source_port=9092,
                                     **servers)

        # blocked source port
        self.assert_tcp_connectivity(destination_port=81,
                                     source_port=9090,
                                     **servers)

    def _remove_rule_and_wait(self, firewall_id, firewall_policy_id,
                              firewall_rule_id):
        self.firewall_policies_client.remove_firewall_rule_from_policy(
            firewall_policy_id=firewall_policy_id,
            firewall_rule_id=firewall_rule_id)
        self._wait_firewall_ready(firewall_id)

    def _delete_firewall(self, ctx):
        self.delete_firewall_and_wait(ctx['fw']['id'])

    def _remove_rule(self, ctx):
        for rule in ctx['fw_rules']:
            self._remove_rule_and_wait(
                firewall_id=ctx['fw']['id'],
                firewall_policy_id=ctx['fw_policy']['id'],
                firewall_rule_id=rule['id'])

    def _disable_rules(self, ctx):
        for rule in ctx['fw_rules']:
            self.firewall_rules_client.update_firewall_rule(
                firewall_rule_id=rule['id'], enabled=False)
        self._wait_firewall_ready(ctx['fw']['id'])

    def _reverse_rules_order(self, ctx):
        self.firewall_policies_client.update_firewall_policy(
            ctx['fw_policy']['id'],
            firewall_rules=list(reversed(ctx['fw_policy']['firewall_rules'])))
        self._wait_firewall_ready(ctx['fw']['id'])

    def _confirm_blocked_one_way(self, from_server, to_server, **_kwargs):

        # one way
        self.assert_no_icmp_connectivity(from_server=from_server,
                                         to_server=to_server)
        self.assert_no_tcp_connectivity(from_server=from_server,
                                        to_server=to_server)

        # other way
        self.assert_icmp_connectivity(from_server=to_server,
                                      to_server=from_server)
        self.assert_tcp_connectivity(from_server=to_server,
                                     to_server=from_server)

    def _confirm_icmp_blocked_but_tcp_allowed(self, from_server, to_server):
        self.assert_no_icmp_connectivity(from_server=from_server,
                                         to_server=to_server)
        self.assert_tcp_connectivity(from_server=from_server,
                                     to_server=to_server)

    def _create_topology(self, router, cidrv4=None, cidrv6=None):
        """Create a topology for testing

        +--------+             +-----------+
        |"server"|             | "subnet"  |
        |   VM   +-------------+ "network" |
        +--------+             +----+------+
                                    |
                                    | router interface port
                               +----+-----+
                               | "router" |
                               +----+-----+
                                    | router gateway port
                                    |
                                    |
                               +----+------------------+
                               | existing network      |
                               | ("public_network_id") |
                               +-----------------------+
        """
        network = self.create_network()
        subnet = self.create_subnet(network, cidr=cidrv4)
        subnet6 = self.create_subnet(network, ip_version=6, cidr=cidrv6)
        self.router_attach(router, subnet)
        self.router_attach(router, subnet6)
        security_group = self.create_open_ssh_security_group()
        self.create_security_group_rule_with_manager(security_group,
                                                     direction='ingress',
                                                     protocol='tcp',
                                                     ethertype='IPv6',
                                                     port_range_min=80,
                                                     port_range_max=9999)
        server = self.create_tenant_server([network],
                                           security_groups=[security_group],
                                           prepare_for_connectivity=True)
        fixed_ip4 = IPAddress(
            server.get_server_ip_in_network(network['name'], 4))
        fixed_ip6 = IPAddress(
            server.get_server_ip_in_network(network['name'], 6))

        return server, fixed_ip4, fixed_ip6

    def _test_firewall_basic(self,
                             block,
                             allow=None,
                             confirm_allowed=None,
                             confirm_blocked=None,
                             ports_for_webserver=(80, )):
        LOG.info('[{}] Begin _test_firewall_basic'.format(self.test_tag))
        if allow is None:
            allow = self._delete_firewall
        if confirm_allowed is None:
            confirm_allowed = self.assert_connectivity
        if confirm_blocked is None:
            confirm_blocked = self.assert_no_connectivity

        LOG.info('[{}] 1. Creating topology'.format(self.test_tag))
        try:
            router = self.get_router()
        except AttributeError:
            # In queens/rocky-em this function is defined as
            # _get_router
            router = self._get_router()

        (server2, server2_fixed_ip4,
         server2_fixed_ip6) = self._create_topology(
             router,
             cidrv4=IPNetwork('20.0.0.0/24'),
             cidrv6=IPNetwork('cafe:bace::/64'))
        (server1, server1_fixed_ip4,
         server1_fixed_ip6) = self._create_topology(
             router,
             cidrv4=IPNetwork('10.0.0.0/24'),
             cidrv6=IPNetwork('cafe:babe::/64'))
        for port in ports_for_webserver:
            self.start_web_server(server1, port=port)
            self.start_web_server(server2, port=port)

        self.sleep(10, 'Naively mitigating slow CI')

        server1.echo_debug_info()
        server2.echo_debug_info()

        LOG.info('[{}] 2. Verify connectivity'.format(self.test_tag))
        self.assert_connectivity(from_server=server1, to_server=server2)

        self.sleep(10, 'Naively mitigating slow CI')

        LOG.info('[{}] 3. Create firewall'.format(self.test_tag))
        ctx = block(server1_fixed_ip=server1_fixed_ip6,
                    server2_fixed_ip=server2_fixed_ip6,
                    router_id=router['id'])

        self.sleep(10, 'Naively mitigating slow CI')

        LOG.info('[{}] 4. Verify no connectivity'.format(self.test_tag))
        confirm_blocked(from_server=server1, to_server=server2)

        LOG.info('[{}] 5. Allow traffic'.format(self.test_tag))
        allow(ctx)

        self.sleep(10, 'Naively mitigating slow CI')

        LOG.info('[{}] 6. Verify connectivity'.format(self.test_tag))
        confirm_allowed(from_server=server1, to_server=server2)

    def test_block_port(self):
        self._test_firewall_basic(
            block=self._block_certain_ports,
            confirm_blocked=self._confirm_certain_ports_blocked,
            allow=self._disable_rules,
            confirm_allowed=self._confirm_certain_ports_allowed,
            ports_for_webserver=(80, 81))

    def test_firewall_block_source_ip(self):
        self._test_firewall_basic(
            block=self._block_source_ip,
            confirm_blocked=self._confirm_blocked_one_way)

    def test_firewall_destination_ip(self):
        self._test_firewall_basic(
            block=self._block_destination_ip,
            confirm_blocked=self._confirm_blocked_one_way)

    def test_firewall_block_icmp(self):
        self._test_firewall_basic(
            block=self._block_icmp,
            confirm_blocked=self._confirm_icmp_blocked_but_tcp_allowed)

    def test_firewall_remove_rule(self):
        self._test_firewall_basic(block=self._block_all_with_default_allow,
                                  allow=self._remove_rule)

    def test_firewall_disable_rule(self):
        self._test_firewall_basic(block=self._block_all_with_default_allow,
                                  allow=self._disable_rules)

    def test_firewall_empty_policy(self):
        self._test_firewall_basic(block=self._empty_policy)

    def test_firewall_all_disabled_rules(self):
        self._test_firewall_basic(block=self._all_disabled_rules)

    @testtools.skipIf(Topology.at_nuage('6.0') or Topology.up_to_nuage('5.4'),
                      reason='VSD-42518')
    def test_firewall_order_rules(self):
        self._test_firewall_basic(block=self._block_all_with_default_allow,
                                  allow=self._reverse_rules_order)