Add forward_guard to host_firewall for a forward chain that drops traffic to guarded guests outside the allowed interfaces, ports and ICMP types
This commit is contained in:
@@ -31,6 +31,11 @@ firewall:
|
||||
dnat: {}
|
||||
# IPv4 source NAT: name -> nft match, e.g. 'oifname "vmbr0"'.
|
||||
masquerade: {}
|
||||
# Forwarded traffic to guarded guests: name -> {ifaces, v4, v6}, where v4 and
|
||||
# v6 are {daddr, tcp: ports, icmp: icmp or icmpv6 types}. Replies and traffic
|
||||
# in on ifaces pass, the listed ports and types pass, the rest to daddr drops;
|
||||
# traffic to other addresses is not filtered.
|
||||
forward_guard: {}
|
||||
ssh_rate_limit: "10/minute burst 5 packets"
|
||||
# EU-27 plus CH, NO, GB, IS, LI (ipdeny country codes). Empty leaves the geo
|
||||
# ports to the admin set; a load peaks at about 60 MB of kernel memory, too much for a 1 GB host.
|
||||
|
||||
@@ -18,6 +18,7 @@ set {{ name }} {
|
||||
{% set guest_match = 'iifname { "' ~ (guest_ifaces | join('", "')) ~ '" }' %}
|
||||
{% set dnat = firewall.dnat | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | list %}
|
||||
{% set masquerade = firewall.masquerade | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %}
|
||||
{% set forward_guard = firewall.forward_guard | default({}, true) | dict2items | rejectattr('value', 'none') | list %}
|
||||
|
||||
# Declare-then-delete makes every load one atomic transaction that replaces
|
||||
# only these tables; Cilium, Docker, NetBird and CrowdSec tables stay untouched.
|
||||
@@ -119,6 +120,32 @@ table inet host {
|
||||
ip6 saddr @geo_v6 accept
|
||||
{% endif %}
|
||||
}
|
||||
{% if forward_guard %}
|
||||
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy accept;
|
||||
{% for guard in forward_guard %}
|
||||
|
||||
# {{ guard.key }}
|
||||
{% set ifaces = guard.value.ifaces | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %}
|
||||
{% for fam, l3, icmp in [('v4', 'ip', 'icmp'), ('v6', 'ip6', 'icmpv6')] if list((guard.value[fam] | default({}, true)).daddr) %}
|
||||
{% set zone = guard.value[fam] %}
|
||||
{% set match = l3 ~ ' daddr { ' ~ list(zone.daddr) ~ ' }' %}
|
||||
{{ match }} ct state established,related accept
|
||||
{% if ifaces %}
|
||||
{{ match }} iifname { "{{ ifaces | join('", "') }}" } accept
|
||||
{% endif %}
|
||||
{% if list(zone.tcp) %}
|
||||
{{ match }} tcp dport { {{ list(zone.tcp) }} } accept
|
||||
{% endif %}
|
||||
{% if list(zone.icmp) %}
|
||||
{{ match }} {{ icmp }} type { {{ list(zone.icmp) }} } accept
|
||||
{% endif %}
|
||||
{{ match }} drop
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
{% if dnat or masquerade %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user