In the first post in the series I left a single network interface for later use in a DMZ or untrusted zone. In this post I will build that additional network and explain why you might want one.
The classic DMZ use case is that of a corporation wishing to expose services on their network to the internet without compromising the safety of the local network. The threat model here is traffic from the internet. With the recent explosion in IoT and the potential for spyware, a new use case was introduced: A separation between trusted and untrusted devices where the latter would cause less harm if malicious or compromised. The threat model here is more “it’s coming from inside the house”. It’s the same reasoning that leads to guest and BYOD networks and the like in a business setting. Depending on use case, you may want more or less access between the two parts but the basic contours of the idea is the same.
As for the form that idea takes, there are two different models of DMZ. I believe the most correct usage of the term is that a DMZ (like it’s military inspiration) is an ‘in between’ zone, guarded on either side by (fire)walls. This is what Wikipedia describes as the dual firewall DMZ. So you would have the DMZ immediately behind the router and firewall facing the internet, and the LAN behind an additional firewall that separates it from the DMZ. The other approach is that of a single router and firewall that has two separate private networks immediately behind it (a single firewall DMZ) with one network often being more open to outside traffic than the other. This is also referred to as a using a ‘screened host firewall’ or – as heard in a recent GamersNexus video – creating an ‘untrusted zone’. There is some overlap between these different architectures and the two uses cases mentioned above. I.e. corporate settings that expose services to the internet are more likely to pick a dual firewall setup and vice versa but it’s not a 1:1 relationship.
Note that the definitions only calls for firewalls, not routers. So, I suppose either zone could be implemented by simply carving out special rules for certain IP ranges within a single LAN (and making sure that IP addresses are only handed out according to very specific rules). AFAICT if the separate zones are also separate, private networks, we can talk about a screened subnet. Or just muddy the waters a bit and call it a DMZ network.
Since I am working with a single router and firewall, I will implement the ‘single firewall’ solution. I will also create a separate network from the LAN (rather than a carved out range) and adopt the GamersNexus term (thanks, Steve) which seems more fitting than the other options available. It might require some additional rules, but I think it makes for a cleaner and more transparent break between the two parts of our network.
Creating the network for the zone
First of all, I need to establish a network on the remaining network interface on my router. I know this to be enp4s0 but ip link should list all interfaces if you’re in doubt. I can do this with an exceedingly simple systemd-networkd configuration in /etc/systemd/network/90-untrusted.network:
[Match]
Name=enp4s0
[Network]
Address=10.0.10.1/24
Note that 10.0.10.1/24 is a separate network from the LAN’s 10.0.0.1/24. I haven’t put up a DHCP server on the network as I have only a single host, as Raspberry Pi 3b running Debian, which can be configured with a static IP. If you need one, it’s simply a matter of cloning the previous network.
Enter the untrusted zone
Let’s establish some ground rules for the zone. Give the grounding in iptables filter table rules, we have had in the previous two posts, it should be easy to translate them in to iptables commands.
- No access to the router from hosts in the untrusted zone.
- Basically, we don’t trust these devices and you shouldn’t be able to access services (eg. SSH) from that side. We may have to make exceptions for some things for basic networking to work but without DHCP on the connection, I cannot think of any.
- We can accomplish this by one of two means. We can explicitly implement a DROP rule on the INPUT chain in the filter table, targetting the
enp4s0interface. Assuming the rule comes before (is higher in the chain than) any broader permissive rules, it will be used on the packets in question. Alternatively, we can make sure that the interface is not included in any of the INPUT chain’s ACCEPT exemptions from the DROP oplicy.
- Host in the zone are allowed to send requests out onto the WAN (but not onto the LAN).
- Whether your use case more closely the first or the second in the introduction, your hosts will in all likelihood need access to send requests out on to the WAN.
- This is accomplished by adding an ACCEPT rule to the FORWARD chain in the filter table, specifying both in- and out-interface, e.g.
iptables -A FORWARD -i enp4s0 -o enp1s0 -j ACCEPT - We have set a policy of DROP on the FORWARD chain in the filter table, so attempts to talk to the LAN should be unsuccessful.
- Hosts in the zone are allowed to receive replies from the WAN to their requests
- Obviously the above rule is useless without allowing a response back.
- Assuming a general non-interface specific
--ctstate RELATED,ESTABLISHEDrule in the FORWARD chain in the filter table like the one implemented in the last post, this should already be allowed.
- Acces from the WAN to hosts in the untrusted zone should be allowed for select services
- Assuming we are using the untrusted zone as a sorta-DMZ, i.e. to offer services to the WAN, be that a Minecraft server, a pet cam, or whatever, we need to allow ‘unsolicited’ traffic through to the relevant socket.
- For this purpose it’s obviously important that the IP address of the host is fixed, so use either static IP addresses or reserved addresses using DHCP.
- We can implement this using a command like this:
iptables -A FORWARD -d 10.0.10.100 -i enp1s0 -o enp4s0 -p tcp -m tcp --dport 8080 -j ACCEPT - Responses to queries like this are similarly covered by a general non-interface specific
--ctstate RELATED,ESTABLISHEDrule in the FORWARD chain in the filter table - If the services are to be offered on the LAN instead, just use the LAN facing device instead of the WAN interface. This is relevant for use cases where you need to talk to the device from devices on the LAN but you don’t trust it not to misuse free access to the LAN. Remote controlling my amplifier with my phone comes to mind as an example.
Assuming that we haven’t set in-interface specific criteria on the MASQUERADE rule we established in the last post (like only applying to traffic coming in on the LAN facing br0 interface), the rule should apply equally to WAN-bound traffic originating from LAN and DMZ. Thus we should now have everything that’s required for devices to live in a semi-isolated environment with access to the internet. If that is all you require no more configuration is needed.
Destinastion: Natal International Airport
If you are looking to expose services to either the WAN or LAN, some further assembly is required. If you are familiar with port forwarding on a standard SOHO router, we will use destination NAT (DNAT) synonymously with port forwarding.
If you are unfamiliar, the basic gist is this: Traffic arrives on the router’s WAN side interface, asking for a proffered service, say on port 8080. The router does not offer this service itself, that is a job for a host in the untrusted zone. So much like in SNAT (just in reverse), it changes the packet’s destination address to that of the host in question. When the response is coming through the other way, the router now changes the source address from the host’s address on the untrusted zone network to it’s own address on the WAN interface.
In practice we implement it using the PREROUTING chain in the nat table:
iptables -A PREROUTING -i enp1s0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 10.0.10.100:8080
Since there are some new things here, let’s break it down:
- As usual, we append (
-A) the rule (i.e. add it to the bottom of the chain, making it the last rule to be checked)… - … but this time to the PREROUTING chain (more on that in a moment).
- We match traffic against three parameters:
- The in-interface (
-i) must be the WAN facing one (enp1s0) - The protocol (
-p) must be tcp - The destination tcp port (
--dport) on the WAN interface (which we can specify thanks to loading the tcp module of iptables using-m) must be 8080
- The in-interface (
- Matching traffic jumps (
-j) to the DNAT chain which takes care of the nitty gritty… - … all we have to do is provide it with the host address and port (
--to-destination) since it can be different to the one that is exposed to the WAN on the WAN side interface)
Note that there is nothing in this part that is specific to the untrusted zone. We could easily do the same with a host on the LAN. It’s just our (quite sensible) policy not to.
Just like we did with source NAT (SNAT) I want to pause for a moment and ask: What is PREROUTING and why is this the place to do DNAT? And once again we will use Phil Hagen’s very good flowchart of packets traversing iptables chains as our reference where we find PREROUTING as a purple rectangle in the upper middle left.
We see that the PREROUTING chain is applied on incoming packets before the routing decision – to forward or keep for myself – is made. This is obviously what the PRE in PREROUTING refers to. Now, our DNAT rules have the capacity to change destination addresses and change traffic that originally had the router itself as destination into forwarded traffic. For that reason we have to apply these rules before the big decision is made. Otherwise we would have to ask the kernel again at a later stage. Now, our example rule does change the destination so packets that are affected by it ends up heading to the right in the diagram (towards various FORWARD chains), rather than downwards (towards various INPUT chains).
As always, save the results of your rules to a script and apply them manually to the router after boot.
Conclusion
Implementing a “DMZ” or untrusted zone is less about new tech than about reflecting on what you are trying to accomplish. It’s about threat models and risk. Will moving a service to an untrusted zone make it ‘safe’? No, but it might be considered a mitigation of risk in that the consequences of a breach will be reduced. However, that depends on the specifics, so it pays to game it out: What is the threat? What happens it a, b, c happens? When the service is on the LAN versus when it’s in the untrusted zone?
Now, I have only established the broad generalities of an untrusted zone. Maybe studying traffic leads you to conclude that WAN bound traffic originating from untrusted devices should be restricted. That is easier when all the junk is segregated out on it’s own network (and network interface). So I’m not saying that there aren’t lots of advantages. However, once again, consider your use case and whether it’s the fun of the exercise and sense of ‘doing the safety thing’ that’s the draw here – or whether there is a genuine network need.
Since we now have all the basic bases covered, next time we will take an overdue look at logging and monitoring. What rules are actually used and effective and which are never activated? What kind of traffic are we seeing and should we reconsider rules based on what we find?
Cover image: red and white stop sign © Matt Seymour, Unsplash License