diff --git a/roles/base/defaults/main.yml b/roles/base/defaults/main.yml index 9cebece..cea3010 100644 --- a/roles/base/defaults/main.yml +++ b/roles/base/defaults/main.yml @@ -2,6 +2,10 @@ # Host firewall (nftables) behaviour knobs. Shared topology (firewall_catalog/ # firewall_zones) lives in group_vars/all, not here. See docs/decisions/020-firewall.md. base__firewall_mgmt_interface: wt0 # SSH accepted only on this iface (NetBird, ADR-016) +base__firewall_control_addr: "" # control-node LAN address (ubongo); SSH allowed from it + # as the guaranteed-management-plane `ssh-from-control` + # source (ADR-021). Empty = no rule. Set in group_vars + # once ubongo exists. base__firewall_ssh_port: 22 base__firewall_rollback_timeout: 45 # seconds before the auto-revert fires on a bad apply base__firewall_confirm_timeout: 20 # seconds to re-establish a fresh connection post-apply diff --git a/roles/base/molecule/default/converge.yml b/roles/base/molecule/default/converge.yml index c219885..66c9ebe 100644 --- a/roles/base/molecule/default/converge.yml +++ b/roles/base/molecule/default/converge.yml @@ -5,6 +5,7 @@ gather_facts: true vars: base__firewall_apply: false + base__firewall_control_addr: 10.10.0.99 # test control-node LAN address firewall_zones: lan: 10.30.0.0/24 srv: 10.20.0.0/24 diff --git a/roles/base/molecule/default/verify.yml b/roles/base/molecule/default/verify.yml index f56e7c3..86326be 100644 --- a/roles/base/molecule/default/verify.yml +++ b/roles/base/molecule/default/verify.yml @@ -19,7 +19,10 @@ - "'type filter hook input priority 0; policy drop;' in nft" - "'ct state established,related accept' in nft" - "'iifname \"wt0\" tcp dport 22 accept' in nft" - fail_msg: "input chain is missing default-deny or the management plane" + - "'ip saddr 10.10.0.99 tcp dport 22 accept' in nft" + fail_msg: >- + input chain is missing default-deny, the wt0 SSH allow, + or the ssh-from-control management-plane rule - name: Assert the lan->reverse_proxy:443 ingress rule (zone source) ansible.builtin.assert: diff --git a/roles/base/templates/nftables.conf.j2 b/roles/base/templates/nftables.conf.j2 index 99806f9..b85ff86 100644 --- a/roles/base/templates/nftables.conf.j2 +++ b/roles/base/templates/nftables.conf.j2 @@ -9,6 +9,9 @@ table inet filter { ct state established,related accept ct state invalid drop iifname "{{ base__firewall_mgmt_interface }}" tcp dport {{ base__firewall_ssh_port }} accept +{% if base__firewall_control_addr %} + ip saddr {{ base__firewall_control_addr }} tcp dport {{ base__firewall_ssh_port }} accept +{% endif %} ip protocol icmp accept ip6 nexthdr ipv6-icmp accept {% for r in base__firewall_resolved %}