feat(zones): Early zone management

This commit is contained in:
v-lafeychine 2023-08-13 18:40:29 +02:00
parent 7e5608081d
commit 1ce8b76555
Signed by: v-lafeychine
GPG key ID: F46CAAD27C7AB0D5
2 changed files with 50 additions and 31 deletions

View file

@ -1,21 +1,20 @@
--- ---
zones: zones:
- name: users-internet-allowed users-internet-allowed:
include:
files: [example.yaml] files: [example.yaml]
- name: mgmt mgmt:
include:
addrs: [10.203.0.0/16] addrs: [10.203.0.0/16]
- name: adm adm:
include:
addrs: [2a09:6840::/29, 10.128.0.0/16] addrs: [2a09:6840::/29, 10.128.0.0/16]
- name: internet internet:
exclude: negate: true
zones: [adm, mgmt] zones: [adm, mgmt]
# interne: negate KO
blacklist: blacklist:
enabled: true enabled: true
addr: [0.0.0.0] addr: [0.0.0.0]

View file

@ -1,7 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from argparse import ArgumentParser, FileType from argparse import ArgumentParser, FileType
from dataclasses import dataclass
from enum import Enum from enum import Enum
from graphlib import TopologicalSorter
from pydantic import ( from pydantic import (
BaseModel, BaseModel,
Extra, Extra,
@ -43,31 +45,43 @@ class PortRange(str):
return range(start, end) return range(start, end)
# ===== First pass: Zones =====
# Zones # Zones
class ZoneName(str): class ZoneName(str):
pass pass
class ZoneEntries(RestrictiveBaseModel): @dataclass
addrs: list[IPvAnyNetwork] | None class Zone:
files: list[FilePath] | None addrs: set[IPvAnyNetwork]
zones: list[ZoneName] | None negate: bool
class Zone(RestrictiveBaseModel): # Zones: Parsing YAML
name: ZoneName class ZoneYAML(RestrictiveBaseModel):
exclude: ZoneEntries | None addrs: set[IPvAnyNetwork] = set()
include: ZoneEntries | None files: set[FilePath] = set()
negate: bool = False
zones: set[ZoneName] = set()
@root_validator()
def validate_mutually_exactly_one(cls, values):
if values.get("exclude") and values.get("include"):
raise ValueError("exclude and include are mutually exclusive")
if values.get("exclude") is None and values.get("include") is None: # Zones: Graph resolver
raise ValueError("exactly one of exclude and include must be set") def convert_to_zone_and_deps(zone_yaml: ZoneYAML) -> tuple[Zone, list[ZoneName]]:
return (Zone(addrs=zone_yaml.addrs, negate=zone_yaml.negate), zone_yaml.zones)
return values
def resolve_zones(zones):
zones = { name: convert_to_zone_and_deps(ZoneYAML(**zone)) for (name, zone) in zones.items() }
zone_name = { name: set(zones) for (name, (_, zones)) in zones.items() }
print(zones)
for name in TopologicalSorter(zone_name).static_order():
print(name)
# TODO: Check negation inclusion
# Blacklist # Blacklist
@ -115,7 +129,8 @@ class Rule(RestrictiveBaseModel):
class ForwardRule(Rule): class ForwardRule(Rule):
dest: ZoneEntries | None # dest: ZoneEntries | None
dest: None
class Filter(RestrictiveBaseModel): class Filter(RestrictiveBaseModel):
@ -131,13 +146,13 @@ class SNat(RestrictiveBaseModel):
class Nat(RestrictiveBaseModel): class Nat(RestrictiveBaseModel):
src: ZoneEntries | None # src: ZoneEntries | None
src: None
snat: SNat snat: SNat
# Root model # Root model
class Firewall(RestrictiveBaseModel): class Firewall(RestrictiveBaseModel):
zones: list[Zone] = []
blacklist: BlackList | None blacklist: BlackList | None
reverse_path_filter: ReversePathFilter | None reverse_path_filter: ReversePathFilter | None
filter: Filter | None filter: Filter | None
@ -149,9 +164,14 @@ def main():
parser.add_argument("file", type=FileType("r"), help="YAML rule file") parser.add_argument("file", type=FileType("r"), help="YAML rule file")
args = parser.parse_args() args = parser.parse_args()
contents = safe_load(args.file)
rules = Firewall(**safe_load(args.file)) zones = resolve_zones(contents.pop("zones"))
print(zones)
exit(0)
rules = Firewall(**contents)
print(rules) print(rules)
return 0 return 0