TT Lab
Get started
Learn Learning paths Courses

Network Fundamentals — Hands-on in a Linux VM

Lock Down One Server with nftables

Continue in TT Lab

This lab runs on a VM

The namespace srv is the server and cli is the client. You write the firewall rules inside srv. If you lock down the VM's own input chain, you block the grading agent too, so do not put any rules in the root namespace.

Goal

With nftables, build "block by default and open only what is needed". Allow reply packets with connection tracking, punch holes by port and by source, count the packets that get dropped, and save the rules to a file.

Why it matters

A firewall is not a list of rules but order and defaults. If the default is drop, whatever you forgot is blocked, and if it is accept, whatever you forgot is open. And if you do not understand connection tracking, you end up writing rules for "outgoing works but replies don't come back" — in fact the most common self-lockout is turning on a firewall while connected over SSH and blocking the replies to your own session. nftables is the successor to iptables, and Kubernetes, Docker, and systemd all create their rules on top of it, so you have to be able to read it to find out "who put in this rule".

Steps

  1. Create the namespaces cli·srv and the veth cli0↔srv0, attach 10.70.0.2/24·10.70.0.1/24, and make ping work.
  2. In srv, start a python3 -m http.server listening on 10.70.0.1:80 and an nc -lk listening on 10.70.0.1:2222.
  3. In srv, create a table inet fw and an input hook chain (policy drop) so that nothing works from cli.
  4. Add three rules to the input chain — allow lo, allow ct state established,related, and allow icmp — so that ping works again.
  5. Add a tcp dport 80 allow rule so that the web works from cli while 2222 still does not.
  6. Add a rule that allows tcp dport 2222 only from ip saddr 10.70.0.2.
  7. Put a counter drop rule at the end of the chain, knock on port 3333 from cli, and then save the nft list chain output showing that counter to /root/fw/dropped.txt.
  8. Save the complete ruleset of srv to /root/fw/ruleset.nft. It must pass the syntax check with nft -c -f.

Notes

Server and client

Create the namespaces cli·srv and the veth cli0↔srv0, attach 10.70.0.2/24·10.70.0.1/24, and make ping work.

cli0 gets 10.70.0.2 in cli, and srv0 gets 10.70.0.1 in srv. Bring lo UP too. ip netns exec cli ping -c 1 10.70.0.1.

Two services

In srv, start a python3 -m http.server listening on 10.70.0.1:80 and an nc -lk listening on 10.70.0.1:2222.

Start both with ip netns exec srv setsid … > 로그 2>&1 < /dev/null & (replace the log placeholder with a log file). ip netns exec srv ss -ltn must show 80 and 2222 as LISTEN, and ip netns exec cli curl -s http://10.70.0.1/ must return something.

Block by default

In srv, create a table inet fw and an input hook chain (policy drop) so that nothing works from cli.

After nft add table inet fw, run nft 'add chain inet fw input { type filter hook input priority 0; policy drop; }'. Now both ping and curl from cli must time out with no response (not refused).

The basic three lines

Add three rules to the input chain — allow lo, allow ct state established,related, and allow icmp — so that ping works again.

The three are nft add rule inet fw input iifname "lo" accept, … ct state established,related accept, and … ip protocol icmp accept. These three are the first lines of almost every firewall.

Open only 80

Add a tcp dport 80 allow rule so that the web works from cli while 2222 still does not.

nft add rule inet fw input tcp dport 80 accept. To check: curl -s -m 2 http://10.70.0.1/ must work, and nc -z -w 2 10.70.0.1 2222 must fail.

Narrow it by source

Add a rule that allows tcp dport 2222 only from ip saddr 10.70.0.2.

nft add rule inet fw input ip saddr 10.70.0.2 tcp dport 2222 accept. Open the port, but only to a specific source — this is how you narrow management ports. ip netns exec cli nc -z -w 2 10.70.0.1 2222 must work.

Count what gets dropped

Put a counter drop rule at the end of the chain, knock on port 3333 from cli, and then save the nft list chain output showing that counter to /root/fw/dropped.txt.

After nft add rule inet fw input counter drop, run ip netns exec cli nc -z -w 1 10.70.0.1 3333 once or twice. In ip netns exec srv nft list chain inet fw input > /root/fw/dropped.txt, counter packets N must be greater than 0. Also keep in mind that to use log inside a netns you need net.netfilter.nf_log_all_netns=1.

Rules as a file

Save the complete ruleset of srv to /root/fw/ruleset.nft. It must pass the syntax check with nft -c -f.

ip netns exec srv nft list ruleset > /root/fw/ruleset.nft. On a real server, this file would become /etc/nftables.conf and be read with nft -f at boot. If nft -c -f /root/fw/ruleset.nft finishes without saying anything, it passes.