Ejemplo n.º 1
0
 def setUp(self):
     self.network_store = StubNetworkStore()
     self.acl_store = StubACLStore(self)
     self.processor = RuleProcessor(self.acl_store, self.network_store)
Ejemplo n.º 2
0
def main():
    # Parse command line args.
    parser = argparse.ArgumentParser(description='Calico ACL Manager')
    parser.add_argument('-c', '--config-file', dest='config_file')
    args = parser.parse_args()

    log_defaults = {'LogFilePath': None,
                    'LogSeverityFile': 'INFO',
                    'LogSeveritySys': 'ERROR',
                    'LogSeverityScreen': 'ERROR',
                    'LocalAddress': '*'   }

    # Read config file.
    config = ConfigParser.ConfigParser(log_defaults)
    config.read(args.config_file or 'acl_manager.cfg')

    plugin_address = config.get('global', 'PluginAddress')
    local_address = config.get('global', 'LocalAddress')
    log_file_path = config.get('log', 'LogFilePath')
    log_file_level = config.get('log', 'LogSeverityFile')
    log_syslog_level = config.get('log', 'LogSeveritySys')
    log_stream_level = config.get('log', 'LogSeverityScreen')

    # Convert log level names into python log levels.
    loglevels = {"none":      None,
                 "debug":     logging.DEBUG,
                 "info":      logging.INFO,
                 "warn":      logging.WARNING,
                 "warning":   logging.WARNING,
                 "err":       logging.ERROR,
                 "error":     logging.ERROR,
                 "crit":      logging.CRITICAL,
                 "critical":  logging.CRITICAL}

    file_level = loglevels[log_file_level.lower()]
    syslog_level = loglevels[log_syslog_level.lower()]
    stream_level = loglevels[log_stream_level.lower()]

    # Configure logging.
    common.default_logging()
    common.complete_logging(logfile=log_file_path,
                            file_level=file_level,
                            syslog_level=syslog_level,
                            stream_level=stream_level)

    log.error("ACL Manager starting (version: %s)",
              pkg_resources.get_distribution('calico'))

    # Create ZeroMQ context.
    context = zmq.Context()
    log.info("pyzmq version is %s" % zmq.pyzmq_version())

    # Create and start components.
    acl_store = ACLStore()
    network_store = NetworkStore()

    publisher = ACLPublisher(context, acl_store, local_address)
    acl_store.start(publisher)

    processor = RuleProcessor(acl_store, network_store)
    network_store.add_processor(processor)

    subscriber = NetworkSubscriber(context, network_store, plugin_address)
Ejemplo n.º 3
0
class TestProcessor(unittest.TestCase):
    """Unit tests for the RuleProcessor class."""
    def setUp(self):
        self.network_store = StubNetworkStore()
        self.acl_store = StubACLStore(self)
        self.processor = RuleProcessor(self.acl_store, self.network_store)

    def tearDown(self):
        self.network_store = None
        self.acl_store = None
        self.processor = None

    # Empty rules and ACLs dictionaries.
    empty_rules = {
        'inbound': [],
        'outbound': [],
        'inbound_default': 'deny',
        'outbound_default': 'deny'
    }
    empty_acls = {
        'v4': {
            'inbound': [],
            'inbound_default': 'deny',
            'outbound': [],
            'outbound_default': 'deny'
        },
        'v6': {
            'inbound': [],
            'inbound_default': 'deny',
            'outbound': [],
            'outbound_default': 'deny'
        }
    }

    def assertDictEqual(self, d1, d2, msg=None):
        """
        This override for assertDictEqual ensures that lists do not need to
        be ordered for dict comparison. It's an unfortunate hack, but c'est la
        vie.
        """
        self.assertEqual(len(d1), len(d2))
        for k, v1 in d1.iteritems():
            self.assertIn(k, d2, msg)
            v2 = d2[k]
            if (isinstance(v1, collections.Iterable)
                    and not isinstance(v1, basestring)):
                self.assertItemsEqual(v1, v2, msg)
            else:
                self.assertEqual(v1, v2, msg)

    def test_case1(self):
        """
        Test simple rules with one group <=> one endpoint <=> one IP address.

        - Group, CIDR and absent rules
        - IPv4 and IPv6 addresses
        - Protocols and ports specified and absent
        - Adding, removing and modifying rules
        """
        # Set up the initial network state
        self.network_store.test_set_groups(['g1', 'g2'])
        self.network_store.test_set_group_members('g1', {'e1': ['10.1.1.1']})
        self.network_store.test_set_group_members('g2', {'e2': ['10.1.1.7']})
        g1_rules = {
            'inbound': [{
                'group': None,
                'cidr': '10.1.3.0/24',
                'protocol': None,
                'port:': '131'
            }],
            'outbound': [{
                'group': 'g2',
                'cidr': None,
                'protocol': 'udp',
                'port': None
            }],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g1', g1_rules)
        g2_rules = deepcopy(self.empty_rules)
        self.network_store.test_set_group_rules('g2', g2_rules)

        # Tell the processor to recalculate its rules
        self.processor.recalc_rules()

        # Check the ACLs produced
        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls = {
            'v4': {
                'inbound': [{
                    'cidr': '10.1.3.0/24',
                    'group': None,
                    'port:': '131',
                    'protocol': None
                }],
                'inbound_default':
                'deny',
                'outbound': [{
                    'cidr': '10.1.1.7/32',
                    'group': None,
                    'port': None,
                    'protocol': 'udp'
                }],
                'outbound_default':
                'deny'
            },
            'v6': {
                'inbound': [],
                'inbound_default': 'deny',
                'outbound': [],
                'outbound_default': 'deny'
            }
        }
        self.acl_store.test_assert_endpoint_acls('e1', 1, e1_acls)
        e2_acls = deepcopy(self.empty_acls)
        self.acl_store.test_assert_endpoint_acls('e2', 1, e2_acls)

        # Add an additional rule to g1
        g1_rules['inbound'].append({
            'group': 'g1',
            'cidr': None,
            'protocol': 'tcp',
            'port': '*'
        })
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls['v4']['inbound'].append({
            'group': None,
            'cidr': '10.1.1.1/32',
            'protocol': 'tcp',
            'port': '*'
        })
        self.acl_store.test_assert_endpoint_acls('e1', 2, e1_acls)
        # The ACLs for endpoint 2 are recalculated superfluously but harmlessly
        self.acl_store.test_assert_endpoint_acls('e2', 2, e2_acls)

        # Change one of g1's rules into an IPv6 CIDR rule
        g1_rules['outbound'][0] = {
            'group': None,
            'cidr': 'fd5f:1::7/96',
            'protocol': 'tcp',
            'port': '80'
        }
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls['v4']['outbound'] = []
        e1_acls['v6']['outbound'].append({
            'group': None,
            'cidr': 'fd5f:1::7/96',
            'protocol': 'tcp',
            'port': '80'
        })
        self.acl_store.test_assert_endpoint_acls('e1', 3, e1_acls)
        self.acl_store.test_assert_endpoint_acls('e2', 3, e2_acls)

        # Remove a rule from g1
        g1_rules['inbound'].pop(0)
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls['v4']['inbound'].pop(0)
        self.acl_store.test_assert_endpoint_acls('e1', 4, e1_acls)
        self.acl_store.test_assert_endpoint_acls('e2', 4, e2_acls)

    def test_case2(self):
        """
        Test multiple IPs per endpoint, EPs per group and groups per EP.

        - Adding and removing IPs to endpoints
        - Adding and removing endpoints to groups
        - Adding and removing additional groups to endpoints
        """
        self.network_store.test_set_groups(['g1', 'g2'])
        self.network_store.test_set_group_members(
            'g1', {'e1': ['10.1.1.1', '10.1.1.2']})
        self.network_store.test_set_group_members(
            'g2',
            {
                'e1': ['10.1.1.1', '10.1.1.2'],  # change transiently
                'e2': ['10.1.1.7']
            })
        g1_rules = {
            'inbound': [],
            'outbound': [{
                'group': 'g2',
                'cidr': None,
                'protocol': None,
                'port': None
            }],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g1', g1_rules)
        g2_rules = {
            'inbound': [{
                'group': None,
                'cidr': 'fd5f:3::/64',
                'protocol': None,
                'port': None
            }],
            'outbound': [],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g2', g2_rules)
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls = deepcopy(self.empty_acls)
        e1_acls['v6']['inbound'] = [{
            'group': None,
            'cidr': 'fd5f:3::/64',
            'protocol': None,
            'port': None
        }]
        e1_acls['v4']['outbound'] = [{
            'group': None,
            'cidr': '10.1.1.1/32',
            'protocol': None,
            'port': None
        }, {
            'group': None,
            'cidr': '10.1.1.2/32',
            'protocol': None,
            'port': None
        }, {
            'group': None,
            'cidr': '10.1.1.7/32',
            'protocol': None,
            'port': None
        }]
        self.acl_store.test_assert_endpoint_acls('e1', 1, e1_acls)

    def test_case3(self):
        """
        Test ignoring empty rules and endpoints.

        - Endpoint UUID ''
        - Empty rule
        """
        # The plugin can pass empty rules or endpoints to ACL Manager, so make
        # sure these work.
        self.network_store.test_set_groups(['g1'])
        self.network_store.test_set_group_members('g1', {
            '': [],
            'e1': '10.1.1.1'
        })

        g1_rules = {
            'inbound': [{
                'group': None,
                'cidr': None,
                'protocol': None,
                'port:': None
            }],
            'outbound': [{
                'group': None,
                'cidr': '10.2.0.0/16',
                'protocol': None,
                'port': '12'
            }],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g1', g1_rules)

        # Tell the processor to recalculate its rules
        self.processor.recalc_rules()

        # Check the ACLs produced
        self.acl_store.test_assert_endpoints(['e1'])
        e1_acls = {
            'v4': {
                'inbound': [],
                'inbound_default':
                'deny',
                'outbound': [{
                    'cidr': '10.2.0.0/16',
                    'group': None,
                    'port': '12',
                    'protocol': None
                }],
                'outbound_default':
                'deny'
            },
            'v6': {
                'inbound': [],
                'inbound_default': 'deny',
                'outbound': [],
                'outbound_default': 'deny'
            }
        }
        self.acl_store.test_assert_endpoint_acls('e1', 1, e1_acls)

    def test_case4(self):
        """
        Test rule which refers to an unknown group.
        """
        # Rules can target another group, but that group may have no members.
        self.network_store.test_set_groups(['g1'])
        self.network_store.test_set_group_members('g1', {'e1': '10.1.1.1'})
        self.network_store.test_set_group_rules(
            'g1', {
                'inbound': [{
                    'group': 'g2',
                    'cidr': None,
                    'protocol': None,
                    'port': None
                }],
                'outbound': [],
                'inbound_default':
                'deny',
                'outbound_default':
                'deny'
            })
        self.processor.recalc_rules()
        self.acl_store.test_assert_endpoints(['e1'])
        self.acl_store.test_assert_endpoint_acls('e1', 1, self.empty_acls)
Ejemplo n.º 4
0
class TestProcessor(unittest.TestCase):
    """Unit tests for the RuleProcessor class."""
    def setUp(self):
        self.network_store = StubNetworkStore()
        self.acl_store = StubACLStore(self)
        self.processor = RuleProcessor(self.acl_store, self.network_store)

    def tearDown(self):
        self.network_store = None
        self.acl_store = None
        self.processor = None

    # Empty rules and ACLs dictionaries.
    empty_rules = {
        'inbound': [],
        'outbound': [],
        'inbound_default': 'deny',
        'outbound_default': 'deny'
    }
    empty_acls = {
        'v4': {
            'inbound': [],
            'inbound_default': 'deny',
            'outbound': [],
            'outbound_default': 'deny'
        },
        'v6': {
            'inbound': [],
            'inbound_default': 'deny',
            'outbound': [],
            'outbound_default': 'deny'
        }
    }

    def test_case1(self):
        """
        Test simple rules with one group <=> one endpoint <=> one IP address.

        - Group, CIDR and absent rules
        - IPv4 and IPv6 addresses
        - Protocols and ports specified and absent
        - Adding, removing and modifying rules
        """
        # Set up the initial network state
        self.network_store.test_set_groups(['g1', 'g2'])
        self.network_store.test_set_group_members('g1', {'e1': ['10.1.1.1']})
        self.network_store.test_set_group_members('g2', {'e2': ['10.1.1.7']})
        g1_rules = {
            'inbound': [{
                'group': None,
                'cidr': '10.1.3.0/24',
                'protocol': None,
                'port:': '131'
            }],
            'outbound': [{
                'group': 'g2',
                'cidr': None,
                'protocol': 'udp',
                'port': None
            }],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g1', g1_rules)
        g2_rules = deepcopy(self.empty_rules)
        self.network_store.test_set_group_rules('g2', g2_rules)

        # Tell the processor to recalculate its rules
        self.processor.recalc_rules()

        # Check the ACLs produced
        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls = {
            'v4': {
                'inbound': [{
                    'cidr': '10.1.3.0/24',
                    'group': None,
                    'port:': '131',
                    'protocol': None
                }],
                'inbound_default':
                'deny',
                'outbound': [{
                    'cidr': '10.1.1.7/32',
                    'group': None,
                    'port': None,
                    'protocol': 'udp'
                }],
                'outbound_default':
                'deny'
            },
            'v6': {
                'inbound': [],
                'inbound_default': 'deny',
                'outbound': [],
                'outbound_default': 'deny'
            }
        }
        self.acl_store.test_assert_endpoint_acls('e1', 1, e1_acls)
        e2_acls = deepcopy(self.empty_acls)
        self.acl_store.test_assert_endpoint_acls('e2', 1, e2_acls)

        # Add an additional rule to g1
        g1_rules['inbound'].append({
            'group': 'g1',
            'cidr': None,
            'protocol': 'tcp',
            'port': '*'
        })
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls['v4']['inbound'].append({
            'group': None,
            'cidr': '10.1.1.1/32',
            'protocol': 'tcp',
            'port': '*'
        })
        self.acl_store.test_assert_endpoint_acls('e1', 2, e1_acls)
        # The ACLs for endpoint 2 are recalculated superfluously but harmlessly
        self.acl_store.test_assert_endpoint_acls('e2', 2, e2_acls)

        # Change one of g1's rules into an IPv6 CIDR rule
        g1_rules['outbound'][0] = {
            'group': None,
            'cidr': 'fd5f:1::7/96',
            'protocol': 'tcp',
            'port': '80'
        }
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls['v4']['outbound'] = []
        e1_acls['v6']['outbound'].append({
            'group': None,
            'cidr': 'fd5f:1::7/96',
            'protocol': 'tcp',
            'port': '80'
        })
        self.acl_store.test_assert_endpoint_acls('e1', 3, e1_acls)
        self.acl_store.test_assert_endpoint_acls('e2', 3, e2_acls)

        # Remove a rule from g1
        g1_rules['inbound'].pop(0)
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls['v4']['inbound'].pop(0)
        self.acl_store.test_assert_endpoint_acls('e1', 4, e1_acls)
        self.acl_store.test_assert_endpoint_acls('e2', 4, e2_acls)

    def test_case2(self):
        """
        Test multiple IPs per endpoint, EPs per group and groups per EP.

        - Adding and removing IPs to endpoints
        - Adding and removing endpoints to groups
        - Adding and removing additional groups to endpoints
        """
        self.network_store.test_set_groups(['g1', 'g2'])
        self.network_store.test_set_group_members(
            'g1', {'e1': ['10.1.1.1', '10.1.1.2']})
        self.network_store.test_set_group_members(
            'g2',
            {
                'e1': ['10.1.1.1', '10.1.1.2'],  # change transiently
                'e2': ['10.1.1.7']
            })
        g1_rules = {
            'inbound': [],
            'outbound': [{
                'group': 'g2',
                'cidr': None,
                'protocol': None,
                'port': None
            }],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g1', g1_rules)
        g2_rules = {
            'inbound': [{
                'group': None,
                'cidr': 'fd5f:3::/64',
                'protocol': None,
                'port': None
            }],
            'outbound': [],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g2', g2_rules)
        self.processor.recalc_rules()

        self.acl_store.test_assert_endpoints(['e1', 'e2'])
        e1_acls = deepcopy(self.empty_acls)
        e1_acls['v6']['inbound'] = [{
            'group': None,
            'cidr': 'fd5f:3::/64',
            'protocol': None,
            'port': None
        }]
        e1_acls['v4']['outbound'] = [{
            'group': None,
            'cidr': '10.1.1.1/32',
            'protocol': None,
            'port': None
        }, {
            'group': None,
            'cidr': '10.1.1.2/32',
            'protocol': None,
            'port': None
        }, {
            'group': None,
            'cidr': '10.1.1.7/32',
            'protocol': None,
            'port': None
        }]
        self.acl_store.test_assert_endpoint_acls('e1', 1, e1_acls)

    def test_case3(self):
        """
        Test ignoring empty rules and endpoints.

        - Endpoint UUID ''
        - Empty rule
        """
        # The plugin can pass empty rules or endpoints to ACL Manager, so make
        # sure these work.
        self.network_store.test_set_groups(['g1'])
        self.network_store.test_set_group_members('g1', {
            '': [],
            'e1': '10.1.1.1'
        })

        g1_rules = {
            'inbound': [{
                'group': None,
                'cidr': None,
                'protocol': None,
                'port:': None
            }],
            'outbound': [{
                'group': None,
                'cidr': '10.2.0.0/16',
                'protocol': None,
                'port': '12'
            }],
            'inbound_default':
            'deny',
            'outbound_default':
            'deny'
        }
        self.network_store.test_set_group_rules('g1', g1_rules)

        # Tell the processor to recalculate its rules
        self.processor.recalc_rules()

        # Check the ACLs produced
        self.acl_store.test_assert_endpoints(['e1'])
        e1_acls = {
            'v4': {
                'inbound': [],
                'inbound_default':
                'deny',
                'outbound': [{
                    'cidr': '10.2.0.0/16',
                    'group': None,
                    'port': '12',
                    'protocol': None
                }],
                'outbound_default':
                'deny'
            },
            'v6': {
                'inbound': [],
                'inbound_default': 'deny',
                'outbound': [],
                'outbound_default': 'deny'
            }
        }
        self.acl_store.test_assert_endpoint_acls('e1', 1, e1_acls)