mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Merge pull request #1094 from Solvik/filter-net
add NetworkValueRejectlistFilter and NetworkValueAllowlistFilter processors
This commit is contained in:
@@ -13,6 +13,11 @@
|
||||
|
||||
* Added ZoneNameFilter processor to enable ignoring/alerting on type-os like
|
||||
octodns.com.octodns.com
|
||||
* NetworkValueAllowlistFilter/NetworkValueRejectlistFilter added to
|
||||
processors.filter to enable filtering A/AAAA records based on value. Can be
|
||||
useful if you have records with non-routable values in an internal copy of a
|
||||
zone, but want to exclude them when pushing the same zone publically (split
|
||||
horizon)
|
||||
* ExcludeRootNsChanges processor that will error (or warn) if plan includes a
|
||||
change to root NS records
|
||||
* Include the octodns special section info in Record __repr__, makes it easier
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#
|
||||
#
|
||||
|
||||
from ipaddress import ip_address, ip_network
|
||||
from itertools import product
|
||||
from logging import getLogger
|
||||
from re import compile as re_compile
|
||||
|
||||
@@ -189,6 +191,91 @@ class NameRejectlistFilter(_NameBaseFilter, RejectsMixin):
|
||||
super().__init__(name, rejectlist)
|
||||
|
||||
|
||||
class _NetworkValueBaseFilter(BaseProcessor):
|
||||
def __init__(self, name, _list):
|
||||
super().__init__(name)
|
||||
self.networks = []
|
||||
for value in _list:
|
||||
try:
|
||||
self.networks.append(ip_network(value))
|
||||
except ValueError:
|
||||
raise ValueError(f'{value} is not a valid CIDR to use')
|
||||
|
||||
def _process(self, zone, *args, **kwargs):
|
||||
for record in zone.records:
|
||||
if record._type not in ['A', 'AAAA']:
|
||||
continue
|
||||
|
||||
ips = [ip_address(value) for value in record.values]
|
||||
if any(
|
||||
ip in network for ip, network in product(ips, self.networks)
|
||||
):
|
||||
self.matches(zone, record)
|
||||
else:
|
||||
self.doesnt_match(zone, record)
|
||||
|
||||
return zone
|
||||
|
||||
process_source_zone = _process
|
||||
process_target_zone = _process
|
||||
|
||||
|
||||
class NetworkValueAllowlistFilter(_NetworkValueBaseFilter, AllowsMixin):
|
||||
'''Only manage A and AAAA records with values that match the provider patterns
|
||||
All other types will be left as-is.
|
||||
|
||||
Example usage:
|
||||
|
||||
processors:
|
||||
only-these:
|
||||
class: octodns.processor.filter.NetworkValueAllowlistFilter
|
||||
allowlist:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.0.0/16
|
||||
- fd00::/8
|
||||
|
||||
zones:
|
||||
exxampled.com.:
|
||||
sources:
|
||||
- config
|
||||
processors:
|
||||
- only-these
|
||||
targets:
|
||||
- route53
|
||||
'''
|
||||
|
||||
def __init__(self, name, allowlist):
|
||||
super().__init__(name, allowlist)
|
||||
|
||||
|
||||
class NetworkValueRejectlistFilter(_NetworkValueBaseFilter, RejectsMixin):
|
||||
'''Reject managing A and AAAA records with value matching a that match the provider patterns
|
||||
All other types will be left as-is.
|
||||
|
||||
Example usage:
|
||||
|
||||
processors:
|
||||
not-these:
|
||||
class: octodns.processor.filter.NetworkValueRejectlistFilter
|
||||
rejectlist:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.0.0/16
|
||||
- fd00::/8
|
||||
|
||||
zones:
|
||||
exxampled.com.:
|
||||
sources:
|
||||
- config
|
||||
processors:
|
||||
- not-these
|
||||
targets:
|
||||
- route53
|
||||
'''
|
||||
|
||||
def __init__(self, name, rejectlist):
|
||||
super().__init__(name, rejectlist)
|
||||
|
||||
|
||||
class IgnoreRootNsFilter(BaseProcessor):
|
||||
'''Do not manage Root NS Records.
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ from octodns.processor.filter import (
|
||||
IgnoreRootNsFilter,
|
||||
NameAllowlistFilter,
|
||||
NameRejectlistFilter,
|
||||
NetworkValueAllowlistFilter,
|
||||
NetworkValueRejectlistFilter,
|
||||
TypeAllowlistFilter,
|
||||
TypeRejectlistFilter,
|
||||
ZoneNameFilter,
|
||||
@@ -161,6 +163,66 @@ class TestNameRejectListFilter(TestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestNetworkValueFilter(TestCase):
|
||||
zone = Zone('unit.tests.', [])
|
||||
for record in [
|
||||
Record.new(
|
||||
zone,
|
||||
'private-ipv4',
|
||||
{'type': 'A', 'ttl': 42, 'value': '10.42.42.42'},
|
||||
),
|
||||
Record.new(
|
||||
zone,
|
||||
'public-ipv4',
|
||||
{'type': 'A', 'ttl': 42, 'value': '42.42.42.42'},
|
||||
),
|
||||
Record.new(
|
||||
zone,
|
||||
'private-ipv6',
|
||||
{'type': 'AAAA', 'ttl': 42, 'value': 'fd12:3456:789a:1::1'},
|
||||
),
|
||||
Record.new(
|
||||
zone,
|
||||
'public-ipv6',
|
||||
{'type': 'AAAA', 'ttl': 42, 'value': 'dead:beef:cafe::1'},
|
||||
),
|
||||
Record.new(
|
||||
zone,
|
||||
'keep-me',
|
||||
{'ttl': 30, 'type': 'TXT', 'value': 'this should always be here'},
|
||||
),
|
||||
]:
|
||||
zone.add_record(record)
|
||||
|
||||
def test_bad_config(self):
|
||||
with self.assertRaises(ValueError):
|
||||
NetworkValueRejectlistFilter(
|
||||
'rejectlist', set(('string', '42.42.42.42/43'))
|
||||
)
|
||||
|
||||
def test_reject(self):
|
||||
filter_private = NetworkValueRejectlistFilter(
|
||||
'rejectlist', set(('10.0.0.0/8', 'fd00::/8'))
|
||||
)
|
||||
|
||||
got = filter_private.process_source_zone(self.zone.copy())
|
||||
self.assertEqual(
|
||||
['keep-me', 'public-ipv4', 'public-ipv6'],
|
||||
sorted([r.name for r in got.records]),
|
||||
)
|
||||
|
||||
def test_allow(self):
|
||||
filter_private = NetworkValueAllowlistFilter(
|
||||
'allowlist', set(('10.0.0.0/8', 'fd00::/8'))
|
||||
)
|
||||
|
||||
got = filter_private.process_source_zone(self.zone.copy())
|
||||
self.assertEqual(
|
||||
['keep-me', 'private-ipv4', 'private-ipv6'],
|
||||
sorted([r.name for r in got.records]),
|
||||
)
|
||||
|
||||
|
||||
class TestIgnoreRootNsFilter(TestCase):
|
||||
zone = Zone('unit.tests.', [])
|
||||
root = Record.new(
|
||||
|
||||
Reference in New Issue
Block a user