05-01: Exercises¶
Question¶
You are hardening a Linux server with iptables. The requirements are:
- Allow SSH (port 22) only from the management subnet 10.10.10.0/24.
- Allow HTTP (port 80) and HTTPS (port 443) from anywhere.
- Drop everything else inbound.
- Allow all outbound traffic.
- Don't break existing/return traffic for connections the server itself initiates.
Write the full set of iptables commands to implement this policy.
Solution¶
Step 1: Decide the default policies¶
Since we want to explicitly allow only specific inbound traffic and drop the rest, while allowing all outbound traffic, set the default (chain policy) for INPUT to DROP and for OUTPUT to ACCEPT:
-Psets the default policy for a chain — what happens to a packet that matches none of the specific rules below.FORWARDis set to DROP too since this server isn't acting as a router.
Step 2: Always allow the loopback interface¶
Many local services (and some system tools) rely on 127.0.0.1. Without this, a DROP-by-default INPUT policy would break local traffic:
-A INPUTappends a rule to the INPUT chain.-i lomatches traffic arriving on the loopback interface.-j ACCEPTis the action (jump target) — accept the packet.
Step 3: Allow established/related return traffic¶
Since we want all outbound connections initiated by the server to work normally, their replies need to be let back in, even though INPUT defaults to DROP:
-m conntrack --ctstate ESTABLISHED,RELATEDmatches packets that belong to a connection this host already initiated (ESTABLISHED) or that are logically related to one (RELATED, e.g., an FTP data channel or an ICMP error tied to an existing flow).- This single rule is what allows outbound-initiated traffic to receive replies without opening the firewall wide.
Step 4: Allow SSH only from the management subnet¶
-p tcprestricts the rule to TCP packets.-s 10.10.10.0/24matches only source addresses in the management subnet.--dport 22matches destination port 22 (SSH).--ctstate NEWmatches only the first packet of a new connection (the SYN); subsequent packets of the same session are already covered by the ESTABLISHED rule in Step 3.
Step 5: Allow HTTP and HTTPS from anywhere¶
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
- No
-srestriction, so any source IP can reach these ports. - Same
NEWstate logic as Step 4 — only new connection attempts need an explicit rule; replies ride on the ESTABLISHED rule.
Step 6: (Implicit) Drop everything else¶
Because the INPUT chain's default policy was set to DROP in Step 1, any packet that doesn't match one of the ACCEPT rules above (loopback, established/related, SSH from the management subnet, HTTP, HTTPS) is dropped automatically. No extra rule is needed, though some administrators add an explicit logging rule for visibility:
(Optional — logs anything about to be dropped, for auditing. The default DROP policy still applies afterward since LOG doesn't stop rule processing on its own without also being followed by DROP, but since DROP is already the chain's default, nothing further is required.)
Final Answer¶
# Default policies
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
# Always allow loopback
iptables -A INPUT -i lo -j ACCEPT
# Allow replies to connections we initiated
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# SSH only from the management subnet
iptables -A INPUT -p tcp -s 10.10.10.0/24 --dport 22 -m conntrack --ctstate NEW -j ACCEPT
# HTTP and HTTPS from anywhere
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
# Everything else inbound is dropped by the default INPUT policy
This gives: SSH restricted to the management subnet, HTTP/HTTPS open to the world, all other inbound traffic dropped by default, and unrestricted outbound traffic with working return paths.