diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 4dc02b32..0fec0f84 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -41,6 +41,7 @@ jobs: pipx inject mkdocs mkdocs-callouts pipx inject mkdocs mike pipx inject mkdocs mkdocs-to-pdf + pipx inject mkdocs mkdocs-glightbox # Workaround, if pipx inject fails to install symlink ln -s "$(pipx environment -V PIPX_LOCAL_VENVS)/mkdocs/bin/mike" \ "$(pipx environment -V PIPX_BIN_DIR)/mike" || true diff --git a/doc/extra.css b/doc/extra.css index 60336ca8..ac6f593d 100644 --- a/doc/extra.css +++ b/doc/extra.css @@ -3,6 +3,10 @@ line-height: 2.6rem; } +.md-typeset code { + font-size: .75em; +} + [data-md-color-primary="orange"] { --md-primary-fg-color: #ff7f2a; --md-primary-bg-color: #5c5f5c; @@ -10,3 +14,13 @@ [data-md-color-primary="black"] { --md-primary-bg-color: #5c5f5c; } + +/* Center Markdown Tables (requires md_in_html extension) */ +.center-table { + text-align: center; +} + +.md-typeset .center-table :is(td,th):not([align]) { + /* Reset alignment for table cells */ + text-align: initial; +} diff --git a/doc/firewall.md b/doc/firewall.md new file mode 100644 index 00000000..7c6ba5c9 --- /dev/null +++ b/doc/firewall.md @@ -0,0 +1,460 @@ +![Firewall](img/firewall.svg){ align=left width="60" } + +# Firewall Documentation + +## Introduction + +A zone-based firewall aims to *simplify network security*. Instead of complex +per-interface rules, you work with **zones** and **policies**. Briefly, ^^zones +define a level of trust^^ for all interfaces or networks assigned to it, and +^^policies regulate the traffic flow^^ between zones. + +![Zone based concept](img/fw-concept.svg){ width=600 } +/// figure-caption +Zones group interfaces, policies control traffic flows. +/// + +Three distinct traffic flows exist: traffic destined for the host itself, +traffic between interfaces within the same zone (intra-zone), and traffic +between different zones (inter-zones). + +--- + +The zone approach is not just more intuitive and maintainable, it allows you +to think more in terms of trust relationships: + +- "internal networks can access the Internet" +- "Internet cannot access my internal network, except this port forward" + +When you add new interfaces to existing zones, they automatically inherit the +established security policies. The amount of actual rules *that matter to +you* is kept to a minimum. + +> [!TIP] Impatient and ready to get going? +> [Fast forward to the Examples: End Device, Home/Office Router, Enterprise Gateway](#examples) + +## Visual Overview + +Use the **zone matrix** to quickly audit your firewall configuration and +identify potential security gaps. It provides an overview and shows the +relationship between zones and the policies that connect them. Each cell in +the matrix represents a potential traffic flow, with rows indicating the +ingress zone and columns the egress zone. + +![Firewall Matrix](img/fw-matrix.png) +/// figure-caption +Example output from show firewall command. +/// + +The matrix uses visual indicators to show the status of each zone and policy: + +**✓ Green checkmark** — traffic is explicitly allowed by policy +**✗ Red cross** — traffic is blocked (default behavior) +**⚠ Yellow warning** — watch out! Some traffic allowed, such as port forwarding rules + +This visualization helps you quickly understand your firewall's behavior and +identify any unintended gaps or overly permissive rules in your configuration. + +> [!TIP] Use the ++question++ key in the CLI +> This admin-exec (top-level) CLI command has sub-commands that you can use to +> drill down on the operational data. Tap the ++question++ key once to see an +> overview after show firewall, or just use the classic UNIX ++tab++ key to +> complete everything until you've found your command. + +## Zones + +Zones are logical groupings of network interfaces or IP networks that share +the same trust level. Each zone has a *default action* that determines what +happens to traffic destined for the host itself (INPUT chain). A LAN zone may +have this set to *accept*, while a DMZ zone may be set to *reject* by default +and only allow a subset of available *services* (e.g., DHCP, DNS, SSH) that +devices in the DMZ can use to reach the host. + +> [!IMPORTANT] +> Interfaces and networks are mutually exclusive in zones — attempting to +> configure both will result in a validation error. When setting up +> [*port forwarding*](#port-forwarding) from one zone to another, the +> destination network must be declared in a zone. + +### Default Zone + +You must specify a default zone. This serves as a safety net: any interface +not explicitly assigned to a zone automatically belongs to the default zone, +ensuring network interfaces remain protected by the firewall. This automatic +assignment is particularly useful when configuring new interfaces (e.g., +VLANs, bridges, or hotplugged devices). + +Choose your default zone carefully — it should be the most restrictive zone +appropriate for unmanaged interfaces. For routers, this is typically the +`wan` zone, but you can of course also set up a dedicated `block` zone. In the +CLI, when first enabling the firewall, a `public` zone is created. See more +about this in the [example below](#end-device-protection). + +> [!IMPORTANT] Remember IP forwarding on interfaces! +> Firewall policies only control whether traffic is allowed on input, to be +> forwarded, or blocked (default). For the actual routing between interfaces +> to work, you must also enable [IP forwarding](networking.md#ipv4-forwarding) +> on the relevant interfaces. + +### Intra-Zone Traffic + +Traffic between different interfaces, or networks, in the same zone is not +forwarded by default. In most cases, if devices on separate interfaces need +to communicate, they should be in different zones with a policy between them. +Alternatively, if you want true LAN-like behavior, [bridge the interfaces][1] +at layer-2 instead of routing between them at layer-3. + +*Intra-zone* forwarding — routing traffic within a single zone — is rarely +needed. But if you do require it, create a policy where both ingress and +egress are set to the same zone, e.g., `lan` → `lan`. + +### Port Forwarding + +Port forwarding, also known as destination NAT (DNAT), redirects inbound +traffic to another address and/or port. This allows external access to +internal services. See [Enterprise Gateway](#enterprise-gateway) for an +example. + +Each zone can have port forwarding rules that apply to traffic arriving at +that zone's interfaces or matching its networks. The forwarded traffic must +then be allowed by appropriate policies to reach the destination zone. + +The *Zone Matrix* shows a ⚠ conditional warning flag, coloring the cell +yellow, when exceptions like port forwarding are active. + +## Policies + +In short, policy rules control traffic **between** zones. By default all +inter-zone (and intra-zone) traffic is rejected. Meaning you must explicitly +allow the traffic flows you intend. + +![Zone based firewall](img/fw-zones.svg){ width=600 } +/// figure-caption +Example of common traffic flows (policies) between zones. +/// + +IP masquerading (SNAT) is a policy setting that applies to traffic egressing +a target zone. (Essential for Internet access from private networks.) + +A policy, like zones, have a default action. If it is *not* set to `accept` +you must specify which services on the host any zone interface and network are +allowed access to. + +> [!NOTE] +> Policy rules apply in-order, the first matching rule with action `drop` will +> terminate the traffic flow. Use action `continue` to allow processing to go +> to the next rule, until the last (implicit) default-drop rule at the end. +> +> The CLI currently does not support reordering rules. As a workaround, save +> your `running-config` to `startup-config`, then exit to the shell and edit +> the file with `edit /cfg/startup-config.cfg`. + +See the [examples below](#enterprise-gateway) for how to set up a policy. The +built-in help system can also be useful: +
admin@example:/config/firewall/policy/lan-to-dmz/> help masquerade
+NAME
+        masquerade 
+DESCRIPTION + Enable masquerading (SNAT) for traffic matching this policy.
+ Matching traffic will have their source IP address changed on egress, + using the IP address of the interface the traffic egresses.";
+admin@example:/config/firewall/policy/lan-to-dmz/> +
+ +### Symbolic Names + +The symbolic names `HOST` and `ANY` are available for use in both `ingress` +and `egress` zones. In fact, the CLI uses inference when first enabling the +firewall to inject a default policy to allow automatic IPv6 address +assignment. + +- `HOST` → `ANY`: Control device to any outbound connection (default: allowed) +- `ANY` → `HOST`: Control what can reach device services (uncommon, usually per-zone) +- Zone → `HOST`: Allow specific zone to access device services + +### Custom Filters + +For more advanced firewall scenarios *custom filters* can be used. Currently +only various ICMP type traffic control is supported. Enough to support the +built-in `allow-host-ipv6` policy and allow certain ICMP types on input or +forward. + +You can inspect this built-in (locked) policy from admin-exec level with the +command: show firewall policy allow-host-ipv6. + +### Default Behavior + +ICMP messages (particularly `echo-request` and `echo-reply`) can be used to +reveal network information for malicious purposes. Therefore, the firewall +blocks ICMP requests by default. This applies unless the zone's default +action is `accept`. + +To enable `echo-request` (IPv4) for any interface, or per zone when action is +set to drop or reject, set up a dedicated policy with `ingress ANY` and `egress +HOST` that use a custom filter to accept that ICMP type. Make this policy the +first rule in your list of policies, and remember to use `continue` for +non-matching traffic. + +Another built-in behavior is automatically allowing "established,related" +return traffic flows. This uses connection tracking - the firewall remembers +outbound connections you initiate and automatically allows the corresponding +inbound response traffic. This means you only need to configure rules for +new connections; the firewall handles return traffic automatically without +additional rules. + +## Services + +Several pre-defined services exist, that cover most use-cases, but you can +also define custom services for applications not covered by the built-in ones. + +The firewall includes over 100 pre-defined services, such as: + +- **`ssh`** — Secure Shell (port 22/tcp) +- **`http`** — Web traffic (port 80/tcp) +- **`https`** — Secure web traffic (port 443/tcp) +- **`dns`** — Domain Name System (port 53/tcp and 53/udp) +- **`dhcp`** — DHCP server (port 67/udp) +- **`dhcpv6-client`** — DHCPv6 client traffic +- **`netconf`** — Network Configuration Protocol (port 830/tcp) +- **`restconf`** — REST-based Network Configuration Protocol (port 443/tcp) + +> [!TIP] Use the ++question++ key in the CLI +> See the YANG model for the full list, or tap the ++question++ key +> when setting up an allowed host service in a zone `set service` + +## Examples + +### End Device Protection + +This is the default firewall setup, useful for end devices on untrusted +networks. It provides maximum protection while allowing essential +connectivity. +
admin@example:/> configure
+admin@example:/config/> edit firewall
+admin@example:/config/firewall/> show
+default public;
+zone public {
+  action reject;
+  description "Public, unknown network. Only SSH and DHCPv6 client allowed.";
+  service dhcpv6-client;
+  service ssh;
+}
+admin@example:/config/firewall/> leave
+
+ +The `reject` action differs from `drop` in that it responds to ICMP messages, +although maybe not how you may think. Pinging the device we may[^1] see this: +
+$ ping 192.168.122.161
+From 192.168.122.161 icmp_seq=1 Packet filtered
+
+ +If we run `tcpdump` it shows us why: +
+$ tcpdump -lni eth0
+20:10:40.245707 IP 192.168.122.1 > 192.168.122.161: ICMP echo request, id 56838, seq 1, length 64
+20:10:40.245961 IP 192.168.122.161 > 192.168.122.1: ICMP host 192.168.122.161 unreachable - admin prohibited filter, length 92
+
+ +The key here is that, yes the device responds, but not with `ICMP reply` but +`ICMP unreachable`, and a little helpful message. + +The default zone is `public`, so all interfaces that are not explicitly +assigned to another zone will be operationally placed in this zone as a +safeguard. Inspect this from admin-exec context with show firewall, as can +be seen in the below screenshot, the only interface `e1` has been assigned +automatically to the public zone. This information is also saved to the +system log. + +![Initial firewall setup with default zone](img/fw-default.png) +/// figure-caption +Zone matrix and firewall overview from show firewall. +/// + +> [!IMPORTANT] +> These defaults are *inferred* for interactive CLI users. Enabling the +> firewall using NETCONF/RESTCONF will not yield the same results. + +[^1]: The output from ping clients differ A LOT. Some do not consider ICMP + unreachable to be a proper response and it will appear as if the device is + not responding at all. Use `tcpdump` or `wireshark` to get to the bottom + of network mysteries. + +### Home/Office Router + +For typical routers that need to protect internal devices while providing +internet access. The LAN zone trusts internal devices, while the WAN zone +blocks external threats. +
admin@example:/> configure
+admin@example:/config/> edit firewall
+admin@example:/config/firewall/> set default wan
+admin@example:/config/firewall/> edit zone lan
+admin@example:/config/firewall/zone/lan/> set description "Internal LAN network - trusted"
+admin@example:/config/firewall/zone/lan/> set action accept
+admin@example:/config/firewall/zone/lan/> set interface eth1
+admin@example:/config/firewall/zone/lan/> set service ssh
+admin@example:/config/firewall/zone/lan/> set service dhcp
+admin@example:/config/firewall/zone/lan/> set service dns
+admin@example:/config/firewall/zone/lan/> end
+admin@example:/config/firewall/> edit zone wan
+admin@example:/config/firewall/zone/wan/> set description "External WAN interface - untrusted"
+admin@example:/config/firewall/zone/wan/> set action drop
+admin@example:/config/firewall/zone/wan/> set interface eth0
+admin@example:/config/firewall/zone/wan/> end
+admin@example:/config/firewall/> edit policy loc-to-wan
+admin@example:/config/firewall/policy/loc-to-wan/> set description "Allow LAN traffic to WAN with SNAT"
+admin@example:/config/firewall/policy/loc-to-wan/> set ingress lan
+admin@example:/config/firewall/policy/loc-to-wan/> set egress wan
+admin@example:/config/firewall/policy/loc-to-wan/> set action accept
+admin@example:/config/firewall/policy/loc-to-wan/> set masquerade
+admin@example:/config/firewall/policy/loc-to-wan/> leave
+
+ +### Enterprise Gateway + +For businesses that need to host public services while protecting internal +resources. We can build upon the Home/Office Router example above and add +a DMZ zone with additional policies for controlled access. +
admin@example:/> configure
+admin@example:/config/> edit firewall zone dmz
+admin@example:/config/firewall/zone/dmz/> set description "Semi-trusted public services"
+admin@example:/config/firewall/zone/dmz/> set action drop
+admin@example:/config/firewall/zone/dmz/> set interface eth1
+admin@example:/config/firewall/zone/dmz/> set service ssh
+admin@example:/config/firewall/zone/dmz/> end
+admin@example:/config/firewall/> edit policy loc-to-wan
+admin@example:/config/firewall/policy/loc-to-wan/> set description "Allow local networks (LAN+DMZ) to WAN with SNAT"
+admin@example:/config/firewall/policy/loc-to-wan/> set ingress dmz
+admin@example:/config/firewall/policy/loc-to-wan/> set egress wan
+admin@example:/config/firewall/policy/loc-to-wan/> set action accept
+admin@example:/config/firewall/policy/loc-to-wan/> set masquerade
+admin@example:/config/firewall/policy/loc-to-wan/> end
+admin@example:/config/firewall/> edit policy lan-to-dmz
+admin@example:/config/firewall/policy/lan-to-dmz/> set description "Allow LAN to manage DMZ services"
+admin@example:/config/firewall/policy/lan-to-dmz/> set ingress lan
+admin@example:/config/firewall/policy/lan-to-dmz/> set egress dmz
+admin@example:/config/firewall/policy/lan-to-dmz/> set action accept
+admin@example:/config/firewall/policy/lan-to-dmz/> end
+admin@example:/config/firewall/> edit zone wan port-forward 8080 tcp
+admin@example:/config/firewall/zone/wan/port-forward/8080/tcp/> set to addr 192.168.2.10
+admin@example:/config/firewall/zone/wan/port-forward/8080/tcp/> set to port 80
+admin@example:/config/firewall/zone/wan/port-forward/8080/tcp/> leave
+
+ +This adds a DMZ zone for public services, updates the internet access policy +to include DMZ traffic, allows LAN management of DMZ services, and forwards +external web traffic to the DMZ server. + +## Logging and Monitoring + +Different log levels are available to monitor and debug firewall behavior. +Configure logging using the CLI: +
+admin@example:/> configure
+admin@example:/config/> edit firewall
+admin@example:/config/firewall/> set logging all
+admin@example:/config/firewall/> leave
+
+ +Firewall logs help you understand traffic patterns and security events. The +CLI admin-exec command show firewall shows the last 10 log messages in the +overview: + +![Firewall logs](img/fw-logs.png){width=100%} +/// figure-caption +Summary of recent logs at the end of show firewall. +/// + +Use the command show log firewall.log to display the full logfile +(remember, the syslog daemon rotates and zips too big log files). You can +also use the follow firewall.log command to continuously monitor +firewall log messages. + +## Netfilter Integration + +The Infix firewall operates through Linux netfilter hooks. Understanding how +the *zones* and *policy* concepts map to these hooks will hopefully help you +understand the firewall's behavior and ease troubleshooting. + +### Packet Flow + +![Netfilter hooks](img/fw-netfilter.svg){width=750} +/// figure-caption +Linux netfilter hooks in layer-3 traffic flow. +/// + +| **Netfilter Hook** | **Function** | **Description** | +|--------------------|--------------|--------------------------------------------------------------------------| +| `prerouting` | ZONE | Classification of incoming traffic, match interfaces/networks with zones | +| `prerouting` | ZONE | Port forwarding (DNAT) from zone configuration | +| `input` | ZONE | Host input filtering (`services`) | +| `input` | ZONE | Default action for non-matching services (`action`) | +| `forward` | POLICY | Allow traffic between zones (inter-zone rules) | +| `postrouting` | POLICY | Masquerade (SNAT) when traffic egresses a zone | + +#### PREROUTING Hook + +- **Zone Classification**: Traffic is tagged based on ingress interface or + source network +- **Port Forwarding**: DNAT from zone configuration occurs before routing decisions +- **Connection Tracking**: Early state establishment for stateful filtering + +#### INPUT Hook + +- **ANY-to-HOST Policies**: Enforces policy rules for traffic destined to the + host itself +- **Zone Services**: Allows configured services (SSH, HTTP, etc.) based on + zone trust level +- **Zone Action**: Applies a default action (accept/reject/drop) for + unmatched traffic + +#### FORWARD Hook + +- **Policy Enforcement**: Primary location for inter-zone traffic filtering +- **Custom Filters**: ICMP and other protocol-specific rules within policies +- **Service Matching**: Allows or denies services based on policy configuration + +#### POSTROUTING Hook + +- **Masquerading**: Source NAT for outbound traffic when policies enable masquerading + + +## Emergency Lockdown + +For security emergencies (active breaches, suspicious activity), the firewall +supports an immediate lockdown mode that blocks ALL traffic. + +> [!DANGER] +> This will immediately terminate all network connections, including SSH. +> Physical console access is required to restore normal operation. It is +> also possible to restore normal operation by power-cycling the device. + +To activate emergency lockdown: + +```json +~$ curl -kX POST -u admin:admin -H "Content-Type: application/yang-data+json" \ + -d '{"infix-firewall:input": {"operation": "now"}}' \ + https://example.local/restconf/operations/infix-firewall:firewall/lockdown-mode +``` + +To cancel lockdown mode (requires console access): + +```json +~$ curl -kX POST -u admin:admin -H "Content-Type: application/yang-data+json" \ + -d '{"infix-firewall:input": {"operation": "cancel"}}' \ + https://example.local/restconf/operations/infix-firewall:firewall/lockdown-mode +``` + +You can check the current lockdown state: + +```json +~$ curl -kX GET -u admin:admin -H 'Accept: application/yang-data+json' \ + https://example.local/restconf/data/infix-firewall:firewall/lockdown +{ + "infix-firewall:firewall": { + "lockdown": false + } +} +``` + +[1]: networking.md#bridging diff --git a/doc/img/firewall.svg b/doc/img/firewall.svg new file mode 100644 index 00000000..bad820f1 --- /dev/null +++ b/doc/img/firewall.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/doc/img/fw-concept.svg b/doc/img/fw-concept.svg new file mode 100644 index 00000000..a598788f --- /dev/null +++ b/doc/img/fw-concept.svg @@ -0,0 +1,4 @@ + + + +
zone UNTRUSTED
zone TRUSTED
Internet
eth0
eth1
policy OUTBOUND
ZBF
\ No newline at end of file diff --git a/doc/img/fw-default.png b/doc/img/fw-default.png new file mode 100644 index 00000000..b0d8a8f4 Binary files /dev/null and b/doc/img/fw-default.png differ diff --git a/doc/img/fw-logs.png b/doc/img/fw-logs.png new file mode 100644 index 00000000..34e5f447 Binary files /dev/null and b/doc/img/fw-logs.png differ diff --git a/doc/img/fw-matrix.png b/doc/img/fw-matrix.png new file mode 100644 index 00000000..6ea2a4ca Binary files /dev/null and b/doc/img/fw-matrix.png differ diff --git a/doc/img/fw-netfilter.svg b/doc/img/fw-netfilter.svg new file mode 100644 index 00000000..593ba0e6 --- /dev/null +++ b/doc/img/fw-netfilter.svg @@ -0,0 +1,4 @@ + + + +
prerouting
postrouting
forward
routing
input
output
Host process
ingress
egress
Bridge layer
ARP layer
Application layer
IP layer
\ No newline at end of file diff --git a/doc/img/fw-zones.svg b/doc/img/fw-zones.svg new file mode 100644 index 00000000..3175cc15 --- /dev/null +++ b/doc/img/fw-zones.svg @@ -0,0 +1,4 @@ + + + +
zone DMZ
zone WAN
zone LAN
ZBFInternet
eth0
eth1
policy loc-to-wan
eth2
policy lan-to-dmz
policy fwd-to-dmz
\ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index b4dfa86c..5d768c0c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,12 +23,13 @@ nav: - Keybindings: cli/keybindings.md - Network Calculator: cli/netcalc.md - Network Monitoring: cli/tcpdump.md - - Quickstart Guide: cli/quick.md + - Quickstart Guide: cli/quick.md - Text Editor: cli/text-editor.md - Upgrading: cli/upgrade.md - Docker Containers: container.md - Networking: - Network Configuration: networking.md + - Firewall Configuration: firewall.md - Quality of Service: qos.md - RMON Counters: eth-counters.md - Tunneling (L2/L3): tunnels.md @@ -98,10 +99,18 @@ theme: icon: material/weather-sunny name: Switch to light mode +# https://squidfunk.github.io/mkdocs-material/reference/formatting/ markdown_extensions: - admonition - attr_list - footnotes + - md_in_html + - pymdownx.blocks.caption + - pymdownx.critic + - pymdownx.caret + - pymdownx.keys + - pymdownx.mark + - pymdownx.tilde - pymdownx.details - pymdownx.superfences - pymdownx.highlight: @@ -118,6 +127,23 @@ plugins: - search - callouts - mike + - glightbox: + touchNavigation: true + loop: false + effect: zoom + slide_effect: slide + width: 100% + height: auto + zoomable: true + draggable: true + skip_classes: + - custom-skip-class-name + auto_themed: true + auto_caption: false + caption_position: bottom + background: black + shadow: false + manual: false - to-pdf: cover: true enabled_if_env: PDF_EXPORT