AxionserveSign in / RegisterEnglish/中文/cn繁体/tw

Firewall Baseline: Default-Deny Plus the Minimal Whitelist

Port audit first, then two copy-paste baselines (ufw five-minute version, nftables standard version), three maintenance routines and the three classic failure

· AxionServe Editorial · 云安全
# The only correct mental model: default-deny plus a minimal whitelist Firewalls have two mental models — "list what to block" and "list what to allow". The first list never ends; the second only needs you to think hard about which doors the business actually uses. **Default-deny inbound + minimal whitelist** is the industry consensus baseline. This piece gives two copy-paste implementations (ufw simple, nftables standard) plus the maintenance discipline. Pair it with the SSH hardening checklist (this is action 6, in full). ## Step 1 — port audit: the evidence for your whitelist Before configuring anything, answer "what does this machine offer the world": ```bash # every listening port with its process — the audit's starting point ss -tlnp # ask three questions per line: what service? must it be public? who uses it? # 127.0.0.1:xxxx = local service (the correct posture for DB/cache) — no whitelist needed # 0.0.0.0:xxxx = open to the internet — each needs an existence reason # typical minimal set: 22 (SSH) + 80/443 (web); DB/Redis/panel ports must NOT appear on 0.0.0.0 ``` Common findings: databases listening on 0.0.0.0 by default (naked from install day), admin panels open to the world, forgotten dev-time services. **The firewall is the last net; the service's own bind address is the first** — move what can bind to 127.0.0.1 first; only the rest enters the whitelist discussion. ## ufw baseline: the five-minute version ```bash ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp comment 'ssh' ufw allow 80/tcp comment 'http' ufw allow 443/tcp comment 'https' # panel-class ports: office network only (an order of magnitude safer than world-open) ufw allow from to any port 8888 proto tcp comment 'panel-office-only' # enable (⚠ confirm 22 is allowed and your SSH session is alive first; port changed? allow the new port first) ufw --force enable ufw status numbered # verify: numbered rule list nc -zv -w3 3306 || echo "3306 closed (expected)" ``` ## nftables baseline: the standard version (distros/hosts without ufw) ```nftables # /etc/nftables.conf — default-deny + state tracking + minimal whitelist flush ruleset table inet filter { chain input { type filter hook input priority 0; policy drop; ct state established,related accept ct state invalid drop iif "lo" accept tcp dport { 22, 80, 443 } accept icmp type echo-request limit rate 5/second accept log prefix "nft-drop: " limit rate 3/minute } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } } ``` Load with `nft -f /etc/nftables.conf` and persist per distro. The log line samples refusals without flooding; the icmp rate limit keeps diagnostics possible without handing scanners a echo amplifier. ## Maintenance discipline: three routines 1. **Whitelist changes are tickets.** Every added port gets a reason, an owner and an expiry review; ports outlive the projects that opened them. 2. **Quarterly re-audit.** Re-run `ss -tlnp` and diff against the whitelist; anything new must justify itself or die. 3. **Egress is a later chapter.** Default-allow outbound is fine at this stage; tighten egress only when a workload demands exfiltration control — doing it early breaks updates and monitoring in ways that train people to disable firewalls. ## Three classic failures - **Enabling before verifying SSH access:** lock yourself out in one command. Confirm your live session survives (keep a console/IPMI channel known). - **Whitelisting the panel to the world "for convenience":** panels are the most-attacked surface on a box; office-IP binding or a tailnet is the price of admission. - **Trusting the cloud security group alone:** security groups and host firewalls are two layers with two owners; when they disagree, the more open one wins. Run both, default-deny both.