Implementation Details

See Examples section in Access Control List documentation as they relate to details described below.

Firewall Interaction

Defguard Gateway does not take control of the entire firewall. Instead, dedicated chains (in NFTables) and anchors (in PF) are used as not to interfere with other rules on the firewall.

NFTables (Linux)

All applied rules are deployed to Defguard Gateway. This means that the firewall on the Gateway that handles the Office-Berlin location should contain appropriate NFTables rules that implement the specified requirements. Let's see how this looks like in practice. Typing nftables list ruleset in the Terminal on a machine running Defguard Gateway should display something like the following:

...
table inet DEFGUARD {
        chain FORWARD {
                type filter hook forward priority filter; policy drop;
                ct state established,related counter packets 0 bytes 0 accept
                ip saddr { 10.100.200.155-10.100.200.156 } ip daddr { 10.1.1.0/24 } counter packets 0 bytes 0 accept comment "ACL 132 - Staff access Berlin ALLOW"
                ip daddr { 10.1.1.0/24 } counter packets 0 bytes 0 drop comment "ACL 132 - Staff access Berlin DENY"
        }
}
...

As you can see, Defguard has created a new table of type inet (the one that handles both IP v4 and v6 addresses). This is to make sure Defguard's configuration won't interfere with your existing NFTables entries.

The FORWARD chain specifies our rules. First you can see the policy drop default, which is a result of setting the Default Deny policy in the location settings. Then the established,related line to skip re-evaluation of established connections.

Finally the two lines that directly deal with our requirement to allow the two users into the network.

ip saddr { 10.100.200.155-10.100.200.156 } ip daddr { 10.1.1.0/24 } counter packets 0 bytes 0 accept comment "ACL 132 - Staff access Berlin ALLOW"

This rule specifies two addresses as the Traffic Source – 10.100.200.155 and 10.100.200.156. Those happen to be device addresses of our two users in the WireGuard VPN network that Defguard Gateway manages for this location. The destination address 10.1.1.0/24 is exactly the network address we specified in the rule. And finally the accept verdict. All together, this rule allows the traffic specified in the UI to the network.

You may also notice that Defguard added a comment to the rule. The comment includes rule's name so that it is easy for you to find the corresponding rule using tools like grep.

Finally, the last line:

ip daddr { 10.1.1.0/24 } counter packets 0 bytes 0 drop comment "ACL 132 - Staff access Berlin DENY"

This line effectively blocks all other traffic to the 10.1.1.0/24 network. As mentioned earlier, the ACL rules in Defguard are self-contained and fully define access for their target resource. This set of rules can now be deployed to any gateway, no regardless of the Default Policy setting, and they will effectively do the same thing.

Gateway deployment with ACL

Under the hood, Access Control functionality uses NFTables to interact with the firewall and implement the rules. This means you'll need kernel version ≥ 5.10 to enable all kernel features required for proper operation.

IP Forwarding

For traffic to flow between your network interfaces on Linux you may also need to enable IP forwarding, if you haven't done it already. This can be achieved by setting the following variable with the following commands:

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1

If the change should be persistent, edit the sysctl configuration file /etc/sysctl.conf and add the following lines to it:

net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1

To load your changes from sysctl.conf, use sysctl -p.

Masquerade

Masquerading between network interfaces falls outside the scope of Defguard’s responsibilities and must be handled by the system administrator. If your environment doesn’t already provide proper routing between the gateway’s interfaces, you may need to enable masquerading to ensure seamless communication.

As a shortcut, Defguard Gateway offers the --masquerade flag (or the DEFGUARD_MASQUERADE=true environment variable), which applies source NAT between all interfaces automatically, saving you from manually configuring masquerade rules at the system level. It results in this masquerade nftables rule:

    chain POSTROUTING {
            ...
            oifname != "lo" counter packets 4 bytes 240 masquerade
    }

Forward chain priority

Defguard creates a forward chain in its namespace to control which forwarded packets are being allowed or blocked. This may interfere with your other nftables rules and chains.

chain FORWARD {
	type filter hook forward priority filter; policy deny;
	ct state established,related counter packets 119 bytes 13404 accept
}

By default this chain has the priority of filter (0). You can edit the priority by setting the DEFGUARD_FW_PRIORITY environment variable (or fw_priority config option) to chosen number, e.g. 1. The higher the priority, the later the chain runs in regard to your other forward chains.

Packet Filter (FreeBSD, NetBSD, macOS)

Packet filter (PF) firewall, is a BSD-licensed stateful packet filtering software originally developed for OpenBSD and now ported to other BSD-based systems like FreeBSD, NetBSD, and macOS.

Defguard Gateway supports Packet Filter (PF) firewall since version 1.4.0.

Anchors

To avoid interference, Defguard Gateway uses custom anchors to add firewall rules. All rules controlled by Defguard are stored in defguard anchor, and inside it, there are anchors dedicated to particular network interfaces.

To see all anchor created by Defguard Gateway, enter:

pfctl -a defguard -sA

To display all rules created for interface wg0, enter:

pfctl -a defguard/wg0 -sr

How to enable Defguard rules in PF

Currently, Defguard Gateway does not include its anchor in the general PF rules. This has be done explicitly, using one of the following methods:

  1. In PF configuration file /etc/pf.conf, which should include a line like the following (see pf.conf(5) manual page for details):

anchor "defguard/*" all
  1. Manually in Terminal, but this will remove all existing top-level rules:

echo 'anchor "defguard/*" all' |pfctl -f -

This is not required for OPNsense plug-in for Defguard Gateway as it automatically creates top-level PF rule to include the appropriate rules.

Rules

To display PF rules for network interface wg0, type the following command:

pfctl -a defguard/wg0 -sr

Rules create in Office-Berlin example should correspond to something like:

block drop in log on wg0 all flags S/SA keep state
pass in log quick on wg0 inet from 10.100.200.155 to 10.1.1.0/24 flags S/SA label "ACL 132 - Staff access Berlin DENY"
pass in log quick on wg0 inet from 10.100.200.156 to 10.1.1.0/24 flags S/SA label "ACL 132 - Staff access Berlin DENY"

Merging destination IP addresses

Destination IPs for a given ACL can be configured in multiple ways:

  • single IP

  • range of IPs

  • IP subnet using CIDR notation

  • list containing arbitrary combination of the above

  • destination aliases

  • component aliases

It is therefore possible to configure some overlapping destinations, for example a 10.0.20.0/24 subnet and then a specific IP like 10.0.20.17 in some alias.

When generating firewall rules we have to be mindful of following limitations regarding our specific implementation:

  • nft rejects overlapping destinations

  • pf does not handle IP ranges, so each IP in range is put in a separate rule

To avoid those issues when creating firewall rules we pre-process destination addresses in a following way:

  • combine all destinations - manually configured, aliases, ranges etc into a single list

  • convert all types of destination (single IPs, ranges, subnets) into IP ranges

  • merge all those ranges into the smallest possible list of non-overlapping ranges

  • extract all possible subnets (with at least 2 IPs) from ranges

This means that our approach is biased towards finding subnets, so the destinations you see in the firewall rules on the gateway itself might differ significantly (in notation, not the content itself) from those you configured in your ACLs.

Last updated

Was this helpful?