feat(base): render nftables ruleset from catalog (+ molecule fixture)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sjat 2026-06-06 18:57:44 +02:00
parent 7dae93e4e1
commit eeab5ed8de
5 changed files with 72 additions and 1 deletions

View file

@ -1,7 +1,22 @@
---
- name: Converge
hosts: all
become: true
gather_facts: true
vars:
base__firewall_apply: false
firewall_zones:
lan: 10.30.0.0/24
srv: 10.20.0.0/24
mgmt: 10.10.0.0/24
firewall_catalog:
reverse_proxy:
host: instance
ingress:
- { from: lan, port: 443, proto: tcp }
photoprism:
host: instance
ingress:
- { from: reverse_proxy, port: 2342, proto: tcp }
roles:
- role: base

View file

@ -26,6 +26,7 @@ provisioner:
host_vars:
instance:
ansible_user: root
ansible_host: 10.20.0.50
verifier:
name: ansible

View file

@ -0,0 +1,30 @@
---
- name: Install nftables
ansible.builtin.apt:
name: nftables
state: present
tags: [firewall]
- name: Ensure nftables drop-in dir exists
ansible.builtin.file:
path: "{{ base__firewall_dropin_dir }}"
state: directory
mode: "0755"
tags: [firewall]
- name: Resolve firewall ingress rules for this host
ansible.builtin.set_fact:
base__firewall_resolved: >-
{{ firewall_catalog | default({})
| resolve_firewall_rules(firewall_zones | default({}),
inventory_hostname, hostvars, groups) }}
tags: [firewall]
- name: Render nftables ruleset (syntax-checked before install)
ansible.builtin.template:
src: nftables.conf.j2
dest: /etc/nftables.conf
mode: "0644"
validate: "nft -c -f %s"
register: base__firewall_render
tags: [firewall]

View file

@ -1 +1,4 @@
---
- name: Configure host firewall (nftables)
ansible.builtin.include_tasks: firewall.yml
tags: [firewall]

View file

@ -0,0 +1,22 @@
#!/usr/sbin/nft -f
# Ansible managed — do not edit by hand. Source: roles/base (ADR-020).
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state established,related accept
ct state invalid drop
iif "{{ base__firewall_mgmt_interface }}" tcp dport {{ base__firewall_ssh_port }} accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
{% for r in base__firewall_resolved %}
ip saddr { {{ r.sources | join(', ') }} } {{ r.proto }} dport {{ r.port }} accept
{% endfor %}
}
chain forward { type filter hook forward priority 0; policy drop; }
chain output { type filter hook output priority 0; policy accept; }
}
include "{{ base__firewall_dropin_dir }}/*.nft"