Feature Specification: Resource firewall

Created: 2026-10-07

Status: Implemented

Input: Reconstructed from the code of core/resources/firewall/ and its policy in core/setups/ at 093e68b6f, pull requests #1238, #1241, #1247 and #1254.

User Scenarios & Testing (mandatory)

The firewall resource decides which ports of a node the internet reaches. It wraps no contract. It adds a gate that runs before the standard NixOS firewall. The shared rules are in the resource family spec.

User Story 1 - Publish the public ports of an application (Priority: P1)

An application that the internet cannot reach does not serve its users. A component requests the TCP or UDP ports of its public protocol. The gate accepts the requested ports and the public ports of the policy from every source. A request publishes a port; it does not make a service listen.

Independent Test: a unit test of the firewall resource.

Acceptance Scenarios:

  1. Given policy ports and request ports, When the gate renders, Then it accepts both sets from every source.

User Story 2 - Restrict the administrative surface (Priority: P1)

An open SSH port on every node is a large attack surface. A hosting provider states its management addresses as admin sources. The gate accepts any port from them, and the admin ports stay served but are not published. Without admin sources, the admin ports are published to everyone.

Independent Test: a unit test of the firewall resource.

Acceptance Scenarios:

  1. Given admin sources, When the gate renders, Then it accepts all traffic from them and does not publish the admin ports.
  2. Given admin sources that gate SSH, When the node runs no SSH server, Then the evaluation fails.

User Story 3 - Keep internal services reachable by peers only (Priority: P2)

Internal services such as databases must not reach the internet, and peers must still reach them. The internal sources are the hypervisor bridge subnet and the real roster addresses. NetBox allocations are not known at evaluation time, so a node that reads its allocation at run time puts its peers into run-time address sets of the gate, each as a single host, since an address with a prefix length admits its full range. The gate accepts the internal sources, the peer sets and the trusted interfaces (always with loopback), and drops other traffic to unpublished ports.

Two kinds of source reach less. An operator source reaches only the operator ports, and a bridge interface reaches only the bridge ports. The gate drops all other traffic from them except ICMP, also where an internal source holds their addresses. The setup also makes the addresses of a cluster (CLUSTER_SOURCES) operator sources, on all nodes but the node with the instances resource, whose operator ports are for the nodes on its bridge.

Independent Test: a unit test of the firewall resource, and a VM test in which the peers of a running tf-incus node change and the gate follows.

Acceptance Scenarios:

  1. Given unpublished served ports, When no source, peer set or trusted interface is set, Then the evaluation fails.
  2. Given a node that reads its allocation at run time, When the gate renders, Then no rule holds a literal allocated or peer address.
  3. Given a running node, When its peers change, Then the peer sets change without a redeploy.

User Story 4 - Open the setup-specific ports (Priority: P3)

The setup adds ports that follow from the deployment, not from an application:

  • A node that answers ACME HTTP-01 challenges, or the SMTP provider with its own certificate, publishes HTTP.
  • A DNS node that an outside party points at publishes DNS over TCP and UDP.
  • The incus node adds the incus API to its admin ports. Its container bridge is a bridge interface that reaches only the ports that the nodes of the hosting provider dial (core/components/hosting-provider/hypervisor-reach.nix), and the operator prefix of the bridge is an operator source.
  • A node that the public uplink gives an address to has no admin ports.

Independent Test: unit tests of the public uplink and of the firewall policy.

Acceptance Scenarios:

  1. Given a node that answers ACME challenges and is a public DNS node, When the policy evaluates, Then it publishes HTTP and DNS together.

Edge Cases

  • The gate renders only with the nftables backend of the NixOS firewall.
  • The gate accepts DHCP, link-local DHCPv6 and established traffic before the source rules, and leaves ICMP to the NixOS firewall.
  • An IPv6 source matches as IPv6. The build checks the rule set, so a malformed CIDR fails the build.

Requirements (mandatory)

Functional Requirements

  • FR-001: The request MUST accept public TCP and UDP ports, none by default.
  • FR-002: The policy MUST accept internal sources, admin sources, admin TCP ports (SSH by default), public TCP and UDP ports, trusted interfaces, operator sources with their TCP and UDP ports, and bridge interfaces with their TCP and UDP ports.
  • FR-003: apply MUST add the policy ports to the ports of all requests.
  • FR-004: The node firewall MUST allow the published ports and the admin ports.
  • FR-005: The admin ports MUST be published only when there are no admin sources.
  • FR-006: The gate MUST run before the standard NixOS firewall, and MUST drop what it does not accept.
  • FR-007: The gate MUST accept the operator ports from the operator sources, then the bridge ports and the public ports from the bridge interfaces, and drop all other traffic from both except ICMP. After that, it MUST accept the trusted interfaces, the internal sources, the run-time peer sets and the admin sources before the published ports.
  • FR-008: The evaluation MUST fail for a source that is empty or has a space, for admin sources that gate SSH without an SSH server, and for unpublished served ports without any source or trusted interface.
  • FR-009: apply MUST set the firewall settings once per machine. A node with more than one machine MUST use the union of their settings.
  • FR-010: The setup MUST give each policy addition as a separate definition, so that the port lists of all additions for one node add up.
  • FR-011: The node firewall MUST allow the bridge ports only on the bridge interfaces.

Key Entities

  • Published port: a port that the gate accepts from every source.
  • Gate source: an address or CIDR in the internal or admin sources, or a host in a run-time peer set.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: The unit tests of the firewall resource, the public uplink and the firewall policy pass.
  • SC-002: The unit test of the hypervisor reach passes: each port that a node of the hosting provider dials on the hypervisor is a bridge port, and each bridge port has a dial.

Assumptions

  • The standard NixOS firewall drops what no rule allows.
  • The roster addresses in the internal sources are the real addresses of the deployment.

Known Deviations

None.