bundles/nftables: store rules in dedicated files instead of nftables.conf
This commit is contained in:
parent
1742f51778
commit
0101e0c92d
11 changed files with 77 additions and 102 deletions
|
@ -37,20 +37,18 @@ def get_static_allocations(metadata):
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'nftables/rules/input/dhcpd',
|
'nftables/rules/10-dhcpd',
|
||||||
)
|
)
|
||||||
def nftables(metadata):
|
def nftables(metadata):
|
||||||
rules = set()
|
rules = set()
|
||||||
for iface in node.metadata.get('dhcpd/subnets', {}):
|
for iface in node.metadata.get('dhcpd/subnets', {}):
|
||||||
rules.add(f'udp dport {{ 67, 68 }} iif {iface} accept')
|
rules.add(f'inet filter input udp dport {{ 67, 68 }} iif {iface} accept')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'nftables': {
|
'nftables': {
|
||||||
'rules': {
|
'rules': {
|
||||||
'input': {
|
|
||||||
# can't use port_rules here, because we're generating interface based rules.
|
# can't use port_rules here, because we're generating interface based rules.
|
||||||
'dhcpd': sorted(rules),
|
'10-dhcpd': sorted(rules),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,6 @@ table inet filter {
|
||||||
ip protocol icmp accept
|
ip protocol icmp accept
|
||||||
|
|
||||||
ip6 nexthdr ipv6-icmp accept
|
ip6 nexthdr ipv6-icmp accept
|
||||||
% for ruleset, rules in sorted(node.metadata.get('nftables/rules/input', {}).items()):
|
|
||||||
|
|
||||||
# ${ruleset}
|
|
||||||
% for rule in rules:
|
|
||||||
${rule}
|
|
||||||
% endfor
|
|
||||||
# / ${ruleset}
|
|
||||||
% endfor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chain output {
|
chain output {
|
||||||
|
@ -40,32 +32,15 @@ table inet filter {
|
||||||
|
|
||||||
icmp type timestamp-request drop
|
icmp type timestamp-request drop
|
||||||
icmp type timestamp-reply drop
|
icmp type timestamp-reply drop
|
||||||
|
|
||||||
% for ruleset, rules in sorted(node.metadata.get('nftables/rules/forward', {}).items()):
|
|
||||||
|
|
||||||
# ${ruleset}
|
|
||||||
% for rule in rules:
|
|
||||||
${rule}
|
|
||||||
% endfor
|
|
||||||
# / ${ruleset}
|
|
||||||
% endfor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table nat {
|
table nat {
|
||||||
chain prerouting {
|
chain prerouting {
|
||||||
type nat hook prerouting priority -100
|
type nat hook prerouting priority -100
|
||||||
|
|
||||||
% for rule in sorted(node.metadata.get('nftables/rules/nat_prerouting', [])):
|
|
||||||
${rule}
|
|
||||||
% endfor
|
|
||||||
}
|
}
|
||||||
chain postrouting {
|
chain postrouting {
|
||||||
type nat hook postrouting priority 100
|
type nat hook postrouting priority 100
|
||||||
|
|
||||||
% for rule in sorted(node.metadata.get('nftables/rules/nat_postrouting', [])):
|
|
||||||
${rule}
|
|
||||||
% endfor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
bundles/nftables/files/rules-template
Normal file
3
bundles/nftables/files/rules-template
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
% for rule in rules:
|
||||||
|
add rule ${rule}
|
||||||
|
% endfor
|
|
@ -15,7 +15,6 @@ directories = {
|
||||||
|
|
||||||
files = {
|
files = {
|
||||||
'/etc/nftables.conf': {
|
'/etc/nftables.conf': {
|
||||||
'content_type': 'mako',
|
|
||||||
'needs': {
|
'needs': {
|
||||||
'directory:/etc/nftables-rules.d',
|
'directory:/etc/nftables-rules.d',
|
||||||
},
|
},
|
||||||
|
@ -30,7 +29,21 @@ files = {
|
||||||
'svc_systemd:nftables:reload',
|
'svc_systemd:nftables:reload',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for ruleset, rules in node.metadata.get('nftables/rules', {}).items():
|
||||||
|
files[f'/etc/nftables-rules.d/{ruleset}'] = {
|
||||||
|
'source': 'rules-template',
|
||||||
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'rules': rules,
|
||||||
|
},
|
||||||
|
'needed_by': {
|
||||||
|
'svc_systemd:nftables',
|
||||||
|
},
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:nftables:reload',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_systemd = {
|
svc_systemd = {
|
||||||
|
|
|
@ -9,12 +9,13 @@ defaults = {
|
||||||
'pacman': {
|
'pacman': {
|
||||||
'packages': {
|
'packages': {
|
||||||
'nftables': {},
|
'nftables': {},
|
||||||
'iptables': {
|
# https://github.com/bundlewrap/bundlewrap/issues/688
|
||||||
'installed': False,
|
# 'iptables': {
|
||||||
'needed_by': {
|
# 'installed': False,
|
||||||
'pkg_pacman:iptables-nft',
|
# 'needed_by': {
|
||||||
},
|
# 'pkg_pacman:iptables-nft',
|
||||||
},
|
# },
|
||||||
|
# },
|
||||||
'iptables-nft': {
|
'iptables-nft': {
|
||||||
'needed_by': {
|
'needed_by': {
|
||||||
'pkg_pacman:nftables',
|
'pkg_pacman:nftables',
|
||||||
|
@ -34,7 +35,7 @@ if not node.has_bundle('vmhost'):
|
||||||
}
|
}
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'nftables/rules/input/port_rules',
|
'nftables/rules/99-port_rules',
|
||||||
)
|
)
|
||||||
def port_rules_to_nftables(metadata):
|
def port_rules_to_nftables(metadata):
|
||||||
# Using this, bundles can simply set up port based rules. This
|
# Using this, bundles can simply set up port based rules. This
|
||||||
|
@ -63,36 +64,33 @@ def port_rules_to_nftables(metadata):
|
||||||
if port != '*':
|
if port != '*':
|
||||||
if ':' in port:
|
if ':' in port:
|
||||||
parts = port.split(':')
|
parts = port.split(':')
|
||||||
port_str = f'dport {{ {parts[0]}-{parts[1]} }} '
|
port_str = f'{proto} dport {{ {parts[0]}-{parts[1]} }}'
|
||||||
else:
|
else:
|
||||||
port_str = f'dport {port} '
|
port_str = f'{proto} dport {port}'
|
||||||
prefix = ''
|
|
||||||
else:
|
else:
|
||||||
port_str = ''
|
port_str = f'meta l4proto {proto}'
|
||||||
prefix = 'meta l4proto '
|
|
||||||
|
|
||||||
if target == '*':
|
if target in ('ipv4', 'ipv6'):
|
||||||
ruleset.add(f'{prefix}{proto} {port_str}accept {comment}')
|
version_str = f'meta nfproto {target}'
|
||||||
elif target == 'ipv4':
|
else:
|
||||||
ruleset.add(f'{prefix}{proto} {port_str}ip version 4 accept {comment}')
|
version_str = ''
|
||||||
elif target == 'ipv6':
|
|
||||||
ruleset.add(f'{prefix}{proto} {port_str}ip6 version 6 accept {comment}')
|
if target in ('*', 'ipv4', 'ipv6'):
|
||||||
|
ruleset.add(f'inet filter input {version_str} {port_str} accept {comment}')
|
||||||
else:
|
else:
|
||||||
resolved = repo.libs.tools.resolve_identifier(repo, target)
|
resolved = repo.libs.tools.resolve_identifier(repo, target)
|
||||||
|
|
||||||
for address in resolved['ipv4']:
|
for address in resolved['ipv4']:
|
||||||
ruleset.add(f'{prefix}{proto} {port_str}ip saddr {address} accept {comment}')
|
ruleset.add(f'inet filter input meta nfproto ipv4 {port_str} ip saddr {address} accept {comment}')
|
||||||
|
|
||||||
for address in resolved['ipv6']:
|
for address in resolved['ipv6']:
|
||||||
ruleset.add(f'{prefix}{proto} {port_str}ip6 saddr {address} accept {comment}')
|
ruleset.add(f'inet filter input meta nfproto ipv6 {port_str} ip6 saddr {address} accept {comment}')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'nftables': {
|
'nftables': {
|
||||||
'rules': {
|
'rules': {
|
||||||
# order does not matter here.
|
# order does not matter here.
|
||||||
'input': {
|
'99-port_rules': sorted(ruleset),
|
||||||
'port_rules': sorted(ruleset),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,12 @@ defaults = {
|
||||||
},
|
},
|
||||||
'nftables': {
|
'nftables': {
|
||||||
'rules': {
|
'rules': {
|
||||||
'input': {
|
'10-wide-dhcp6c': [
|
||||||
'wide-dhcp6c': [
|
'inet filter input udp dport { 546, 547 } ip6 saddr ff00::/12 accept',
|
||||||
'udp dport { 546, 547 } ip6 saddr ff00::/12 accept',
|
'inet filter input udp dport { 546, 547 } ip6 saddr fe80::/10 accept',
|
||||||
'udp dport { 546, 547 } ip6 saddr fe80::/10 accept',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
'icinga2_api': {
|
'icinga2_api': {
|
||||||
'wide-dhcp6c': {
|
'wide-dhcp6c': {
|
||||||
'services': {
|
'services': {
|
||||||
|
|
|
@ -18,16 +18,6 @@ defaults = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'nftables': {
|
|
||||||
'rules': {
|
|
||||||
'forward': {
|
|
||||||
'wireguard': [
|
|
||||||
'iif wg0 accept',
|
|
||||||
'oif wg0 accept',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'wireguard': {
|
'wireguard': {
|
||||||
'privatekey': repo.libs.keys.gen_privkey(repo, f'{node.name} wireguard privatekey'),
|
'privatekey': repo.libs.keys.gen_privkey(repo, f'{node.name} wireguard privatekey'),
|
||||||
},
|
},
|
||||||
|
@ -221,17 +211,20 @@ def interface_ips(metadata):
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'nftables/rules/nat_postrouting',
|
'nftables/rules/10-wireguard',
|
||||||
)
|
)
|
||||||
def snat(metadata):
|
def snat(metadata):
|
||||||
if not node.has_bundle('nftables'):
|
if not node.has_bundle('nftables'):
|
||||||
raise DoNotRunAgain
|
raise DoNotRunAgain
|
||||||
|
|
||||||
rules = set()
|
rules = {
|
||||||
|
'inet filter forward iif wg0 accept',
|
||||||
|
'inet filter forward oif wg0 accept',
|
||||||
|
}
|
||||||
|
|
||||||
for config in metadata.get('wireguard/peers', {}).values():
|
for config in metadata.get('wireguard/peers', {}).values():
|
||||||
if 'snat_to' in config:
|
if 'snat_to' in config:
|
||||||
rules.add('ip saddr {} ip daddr != {} snat to {}'.format(
|
rules.add('nat postrouting ip saddr {} ip daddr != {} snat to {}'.format(
|
||||||
config['my_ip'],
|
config['my_ip'],
|
||||||
config['their_ip'],
|
config['their_ip'],
|
||||||
config['snat_to'],
|
config['snat_to'],
|
||||||
|
@ -240,7 +233,7 @@ def snat(metadata):
|
||||||
return {
|
return {
|
||||||
'nftables': {
|
'nftables': {
|
||||||
'rules': {
|
'rules': {
|
||||||
'nat_postrouting': rules,
|
'10-wireguard': sorted(rules),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,22 +102,18 @@ nodes['home.router'] = {
|
||||||
},
|
},
|
||||||
'nftables': {
|
'nftables': {
|
||||||
'rules': {
|
'rules': {
|
||||||
'forward': {
|
'50-router': [
|
||||||
'router': [
|
|
||||||
# This is a router. Allow forwarding traffic for internal networks.
|
# This is a router. Allow forwarding traffic for internal networks.
|
||||||
'ct state { related, established } accept',
|
'inet filter forward ct state { related, established } accept',
|
||||||
'iif enp1s0.23 oif ppp0 accept',
|
'inet filter forward iif enp1s0.23 oif ppp0 accept',
|
||||||
'iif enp1s0.42 accept',
|
'inet filter forward iif enp1s0.42 accept',
|
||||||
|
|
||||||
# yaaaaay, IPv6! No NAT!
|
# yaaaaay, IPv6! No NAT!
|
||||||
'ip6 nexthdr ipv6-icmp accept',
|
'inet filter forward ip6 nexthdr ipv6-icmp accept',
|
||||||
'tcp dport 22 accept',
|
'inet filter forward tcp dport 22 accept',
|
||||||
|
'nat prerouting tcp dport 2022 dnat 172.19.138.20:22',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'nat_prerouting': {
|
|
||||||
'tcp dport 2022 dnat 172.19.138.20:22',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'nginx': {
|
'nginx': {
|
||||||
'restrict-to': {
|
'restrict-to': {
|
||||||
|
|
|
@ -51,6 +51,11 @@ nodes['htz-cloud.influxdb'] = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
#'openssh': {
|
||||||
|
# 'restrict-to': {
|
||||||
|
# 'versatel',
|
||||||
|
# },
|
||||||
|
#},
|
||||||
'vm': {
|
'vm': {
|
||||||
'cpu': 1,
|
'cpu': 1,
|
||||||
'ram': 2,
|
'ram': 2,
|
||||||
|
|
|
@ -181,14 +181,12 @@ nodes['htz-cloud.miniserver'] = {
|
||||||
},
|
},
|
||||||
'nftables': {
|
'nftables': {
|
||||||
'rules': {
|
'rules': {
|
||||||
'input': {
|
'50-sophie-weechat': [
|
||||||
'sophie-weechat': [
|
'inet filter input udp dport { 60000-61000 } accept',
|
||||||
'udp dport { 60000-61000 } accept',
|
'inet filter input tcp dport 9001 accept',
|
||||||
'tcp dport 9001 accept',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
'nginx': {
|
'nginx': {
|
||||||
'vhosts': {
|
'vhosts': {
|
||||||
'matrix-dimension': {
|
'matrix-dimension': {
|
||||||
|
|
|
@ -275,14 +275,12 @@ nodes['rx300'] = {
|
||||||
},
|
},
|
||||||
'nftables': {
|
'nftables': {
|
||||||
'rules': {
|
'rules': {
|
||||||
'input': {
|
'50-kunsi-weechat': [
|
||||||
'kunsi-weechat': [
|
'inet filter input udp dport { 60000-61000 } accept',
|
||||||
'udp dport { 60000-61000 } accept',
|
'inet filter input tcp dport 9001 accept',
|
||||||
'tcp dport 9001 accept',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
'nginx': {
|
'nginx': {
|
||||||
'security.txt': {
|
'security.txt': {
|
||||||
'contact': 'mailto:security@kunsmann.eu',
|
'contact': 'mailto:security@kunsmann.eu',
|
||||||
|
|
Loading…
Reference in a new issue