Always combine IP set data with static network definitions from NetBox
Before we relied on the combined data being present in ipsets.json when generating a new config, but ipsets.json is only updated through the form at /ipsets. So submitting any other form after changing NetBox definitions might crash when trying to find an entry from networks.json in ipsets.json. Now we introduce a helper functon to always read both files and combine the prefixes fron networks.json with ipsets.json. This way it is not necessary to save a new ipsets.json before other changes. Also don’t crash when enumerating networks for each VPN group.
This commit is contained in:
parent
b6c191e2ce
commit
048195c45c
5 changed files with 41 additions and 26 deletions
|
@ -18,6 +18,7 @@ import flask.cli
|
|||
import ldap3
|
||||
|
||||
from . import db
|
||||
from . import ipsets
|
||||
|
||||
def init_app(app):
|
||||
app.cli.add_command(generate)
|
||||
|
@ -49,7 +50,6 @@ def save_config():
|
|||
# Just load required settings here but keep the database unlocked
|
||||
# while we load group memberships from LDAP.
|
||||
with db.locked():
|
||||
ipsets = db.read('ipsets')
|
||||
settings = db.read('settings')
|
||||
|
||||
# Build LDAP query for users and groups.
|
||||
|
@ -72,15 +72,15 @@ def save_config():
|
|||
# Now read the settings again while keeping the database locked until
|
||||
# config files are generated, and increment version before unlocking.
|
||||
with db.locked():
|
||||
ipsets = db.read('ipsets')
|
||||
sets = ipsets.read()
|
||||
wireguard = db.read('wireguard')
|
||||
settings = db.read('settings')
|
||||
version = settings['version'] = int(settings.get('version') or '0') + 1
|
||||
|
||||
# Find networks accessible to VPN users for each AD group.
|
||||
vpn_groups = {e['vpn'] for e in ipsets.values() if e.get('vpn')}
|
||||
vpn_groups = {e['vpn'] for e in sets.values() if e.get('vpn')}
|
||||
group_networks = {
|
||||
group: [name for name, data in ipsets.items() if data['vpn'] == group] for group in vpn_groups
|
||||
group: [name for name, data in sets.items() if data.get('vpn') == group] for group in vpn_groups
|
||||
}
|
||||
|
||||
# Add VPN addresses to IP sets.
|
||||
|
@ -92,9 +92,9 @@ def save_config():
|
|||
for group in user_groups.get(key.get('user', ''), ()):
|
||||
key_networks |= set(group_networks.get(group, ()))
|
||||
for network in key_networks:
|
||||
ipsets[network]['ip'].append(f'{ip}/32')
|
||||
sets[network]['ip'].append(f'{ip}/32')
|
||||
if ip6 := key.get('ip6'):
|
||||
ipsets[network]['ip6'].append(ip6)
|
||||
sets[network]['ip6'].append(ip6)
|
||||
|
||||
# Create config files.
|
||||
output = pathlib.Path.home() / 'config' / f'{version}'
|
||||
|
@ -113,7 +113,7 @@ def save_config():
|
|||
def make_set(ips):
|
||||
# return "elements = { ip1, ip2, … }", prefixed with "# " if no ips
|
||||
return f'{"" if ips else "# "}elements = {{ {", ".join(ips)} }}'
|
||||
for name, data in ipsets.items():
|
||||
for name, data in sets.items():
|
||||
f.write(nft_set.format(name=name, ips=make_set(data.get('ip', ()))))
|
||||
f.write(nft_set6.format(name=name, ips=make_set(data.get('ip6', ()))))
|
||||
f.write('\n')
|
||||
|
@ -132,14 +132,14 @@ def save_config():
|
|||
# Print dynamic NAT rules.
|
||||
with open(output / 'etc/nftables.d/nat.nft', 'w', encoding='utf-8') as f:
|
||||
nft_nat = 'iif @inside oif @outside ip saddr @{name} snat to {nat}\n'
|
||||
for name, data in ipsets.items():
|
||||
for name, data in sets.items():
|
||||
if nat := data.get('nat'):
|
||||
f.write(nft_nat.format(name=name, nat=nat))
|
||||
|
||||
# Print forwarding rules.
|
||||
with open(output / 'etc/nftables.d/forward.nft', 'w', encoding='utf-8') as f:
|
||||
# Forwarding rules for VPN users.
|
||||
if vpn_networks := sorted(name for name, data in ipsets.items() if data.get('vpn')):
|
||||
if vpn_networks := sorted(name for name, data in sets.items() if data.get('vpn')):
|
||||
nft_forward = 'iif @inside oif @inside ip saddr @{name} ip daddr @{name} accept\n'
|
||||
nft_forward6 = 'iif @inside oif @inside ip6 saddr @{name}/6 ip6 daddr @{name}/6 accept\n'
|
||||
f.write('# forward from the VPN interface to physical networks and back\n')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue