Security Basics Lesson 15 – Firewalls & Access Control | Dataplexa
Section II · Lesson 15

Firewalls & Access Control

A firewall is a gatekeeper that decides which network traffic is allowed in, which is allowed out, and which gets dropped silently on the floor. Access control is the broader discipline of deciding who — and what — gets to reach which resources. Together, they form the first and most fundamental layer of any network defence.

This lesson covers

How firewalls work → Stateless vs stateful filtering → iptables rules hands-on → ufw for practical server hardening → ACLs and the principle of least privilege → How attackers probe and bypass firewalls → What to lock down first

How firewalls actually work

Every packet of data travelling across a network has a source IP, a destination IP, a source port, a destination port, and a protocol. A firewall reads those five values and compares them against a list of rules — top to bottom, in order — until it finds a match. When it matches, it either allows the packet through or drops it. If nothing matches, the default policy applies.

That default policy is critical. A firewall configured to allow everything by default and only block specific things is called a blacklist approach — and it's fundamentally weak, because you have to know about every bad thing in advance to block it. A firewall configured to deny everything by default and only allow specific things is a whitelist approach — and it's the correct one. Block all, then open only what you need.

Stateless Firewall

Examines each packet in isolation. Doesn't know whether a packet belongs to an established connection or is a fresh attempt. Fast, but easy to bypass — an attacker can craft packets that look like replies to connections that never existed.

Stateful Firewall

Tracks the state of every active connection. Knows whether an incoming packet is part of an established, legitimate session or is unsolicited. The standard for modern network perimeters. Most Linux firewalls (iptables, nftables) operate this way.

There's also a third tier — application-layer firewalls (sometimes called next-generation firewalls or WAFs). These go deeper than ports and IPs. They can read the actual content of HTTP requests, block specific URLs, detect SQL injection attempts in web traffic, and make decisions based on what the application is actually doing rather than just which port it's using. We cover those in the web security section.

iptables — the engine under the hood

iptables is the low-level firewall engine built into the Linux kernel. It's been there since Linux 2.4 and still powers most Linux firewalls today, even when tools like ufw or firewalld sit on top of it. Understanding iptables rules means you understand what every higher-level tool is actually doing.

iptables organises rules into chains — INPUT (traffic coming into the machine), OUTPUT (traffic leaving the machine), and FORWARD (traffic passing through the machine to somewhere else). Each rule in a chain specifies what to match and what to do when it matches: ACCEPT, DROP, or REJECT. DROP silently discards the packet. REJECT discards it and sends an error back to the sender.

# View all current iptables rules with line numbers
sudo iptables -L -v -n --line-numbers

# --- BUILDING A BASIC SECURE RULESET ---

# Step 1: Set default policies — deny everything incoming and forwarded
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# Step 2: Allow loopback traffic (required for local services to communicate)
sudo iptables -A INPUT -i lo -j ACCEPT

# Step 3: Allow established and related connections back in
# (so replies to your outbound requests are not blocked)
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Step 4: Allow SSH on port 22 (replace with your actual SSH port if changed)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Step 5: Allow HTTP and HTTPS for a web server
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Step 6: Log and drop everything else
sudo iptables -A INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4
sudo iptables -A INPUT -j DROP

# Save rules so they persist after reboot (Debian/Ubuntu)
sudo iptables-save | sudo tee /etc/iptables/rules.v4
# Output of: sudo iptables -L -v -n --line-numbers (after applying rules above)

Chain INPUT (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1      847  112K ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
2     9823 8412K ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
3      142  8520 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
4     2401  140K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80
5     1893  103K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443
6       38  2280 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4 prefix "IPT-DROP: "
7       38  2280 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain FORWARD (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

What just happened

The INPUT chain default policy is now DROP — anything not explicitly allowed gets silently discarded. Rule 2 is the stateful connection tracking rule — the ESTABLISHED,RELATED match allows replies to connections you initiated, so browsing the web still works. Rules 3–5 open only SSH, HTTP, and HTTPS. Rules 6–7 log every dropped packet with the prefix "IPT-DROP:" and then drop it — those logs end up in /var/log/kern.log and are extremely useful for spotting scan attempts.

ufw — practical firewall management

iptables is powerful but verbose. For day-to-day server management, most teams use ufw (Uncomplicated Firewall) — a frontend that translates simple commands into iptables rules. It ships with Ubuntu and is the right tool for hardening individual servers quickly without writing raw iptables syntax.

# Check current ufw status
sudo ufw status verbose

# Enable ufw (default policy: deny incoming, allow outgoing)
sudo ufw enable

# Allow SSH before enabling — or you will lock yourself out
sudo ufw allow ssh

# Allow specific ports
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Allow a port range (e.g. passive FTP data ports)
sudo ufw allow 49152:65535/tcp

# Allow traffic from a specific trusted IP only (e.g. your office)
sudo ufw allow from 203.0.113.50 to any port 22

# Deny a specific IP that is hammering your server
sudo ufw deny from 185.220.101.47

# Delete a rule by number
sudo ufw status numbered
sudo ufw delete 3

# Rate-limit SSH to slow down brute-force attempts
# Blocks IPs that attempt 6+ connections in 30 seconds
sudo ufw limit ssh

# View rules with full detail
sudo ufw status verbose
$ sudo ufw status verbose

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
22/tcp                     ALLOW IN    203.0.113.50
Anywhere                   DENY IN     185.220.101.47
49152:65535/tcp            ALLOW IN    Anywhere
22/tcp (v6)                LIMIT IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

Always allow SSH before enabling ufw

If you run sudo ufw enable on a remote server without first allowing SSH, you will immediately lose access. The default deny policy kicks in the moment ufw activates. Run sudo ufw allow ssh first, every time, without exception. If you do lock yourself out, you'll need console access through your cloud provider's web interface to fix it.

Access Control Lists and least privilege

A firewall controls access at the network level — which IPs and ports can talk to which. Access Control Lists (ACLs) extend this concept to resources: files, directories, APIs, database tables. The principle behind both is the same — least privilege: every user, service, and system should have access to exactly what it needs to do its job, and nothing more.

In practice this means: your web server process shouldn't run as root. Your database user for the application should only have SELECT, INSERT, and UPDATE on the specific tables it needs — not DROP TABLE, not full schema access. Your monitoring agent should be able to read logs but not write to the filesystem. Every excess permission is a privilege an attacker can abuse if they compromise that account.

# View ACLs on a file (Linux extended ACLs via getfacl)
getfacl /var/www/html/config.php

# Set specific ACL — give the web app user read-only access
# without changing the standard Unix permissions
sudo setfacl -m u:www-data:r /var/www/html/config.php

# Give a deployment user read+execute on a directory recursively
sudo setfacl -Rm u:deploy:rx /var/www/html/

# Remove all ACL entries for a specific user
sudo setfacl -x u:olduser /var/www/html/config.php

# Check what the web server process is running as
ps aux | grep nginx
# getfacl /var/www/html/config.php
file: var/www/html/config.php
owner: root
group: www-data
user::rw-
user:www-data:r--          # www-data can read but not write or execute
user:deploy:r-x            # deploy user can read and execute
group::r--
mask::r-x
other::---                 # no one else gets any access

# ps aux | grep nginx
root      1134  0.0  0.1  nginx: master process /usr/sbin/nginx
www-data  1135  0.0  0.2  nginx: worker process
www-data  1136  0.0  0.2  nginx: worker process

What just happened

The ACL output shows granular per-user permissions beyond the standard Unix rwx model. other::--- means anyone not explicitly listed gets zero access. The nginx process output confirms the master process runs as root (needed to bind to port 80) but worker processes — the ones actually handling requests — run as www-data, a low-privilege account. If an attacker exploits a vulnerability in nginx, they get www-data privileges — not root. That single configuration decision limits the blast radius of a compromise significantly.

How attackers probe and bypass firewalls

Attackers don't knock on the front door. They map the entire perimeter first. The standard tool for this is nmap — a port scanner that sends probes to every port and categorises the responses as open, closed, or filtered.

A port that responds is open. A port that sends back a TCP RST is closed — the service isn't running, but the firewall isn't blocking it either. A port that returns nothing at all — that's filtered, meaning a firewall is silently dropping the probe. Attackers use this information to build a map of what's running, which ports the firewall is protecting, and which ones it isn't.

Common bypass techniques

Tunnelling over allowed ports: If port 443 is open for HTTPS, an attacker can tunnel arbitrary traffic through it — SSH, C2 communications, data exfiltration — because the firewall only sees "HTTPS traffic on port 443" and allows it. Application-layer inspection is required to catch this.

Firewall rule ordering exploits: Rules are evaluated top to bottom. If a broad ALLOW rule appears before a specific DENY rule, the ALLOW fires first and the DENY never runs. Misconfigured rule order is a common firewall mistake.

IPv6 blind spots: Many organisations harden their IPv4 firewall rules thoroughly but forget that the same server also has an IPv6 address — with no rules applied to it at all.

What to lock down first on any new server

Every new server you spin up should go through the same hardening checklist before it touches production traffic. This isn't comprehensive — it's the minimum that should be non-negotiable.

1. Enable the firewall with deny-all default

First action on every new server. Enable ufw, set default deny incoming, allow only the specific ports this server needs. Takes two minutes. Closes every accidental exposure immediately.

2. Restrict SSH to key-based authentication only

Disable password authentication in /etc/ssh/sshd_config. Set PasswordAuthentication no. Without this, every brute-force script on the internet will attempt your SSH port indefinitely.

3. Run services as non-root users

Check what user each service runs as with ps aux. Web servers, database processes, application runtimes — none of these should run as root. Create dedicated service accounts with only the permissions each service requires.

4. Apply the same rules to IPv6

If you're using ufw, run sudo ufw default deny incoming — it applies to both IPv4 and IPv6. If using iptables directly, remember to apply equivalent rules with ip6tables. An unconfigured IPv6 stack on a hardened IPv4 server is a wide-open back door.

5. Enable logging on dropped packets

Add a LOG rule before your final DROP rule in iptables, or enable ufw logging with sudo ufw logging on. You can't investigate what you didn't record. Dropped packet logs are often the first sign of a port scan or targeted attack in progress.

Instructor's Note

The most dangerous firewall configuration isn't one with no rules — it's one that someone set up years ago, added rules to over time without a documented reason for each one, and nobody has audited since. Rules accumulate. Services get decommissioned and their firewall rules don't. Run sudo iptables -L -v -n --line-numbers on any production server you inherit and count how many rules have zero packet hits. Those rules are either redundant or they're blocking something nobody knew was being blocked. Either way, they need reviewing.


Practice Questions

A correctly hardened server firewall should set the default INPUT policy to what — allow or deny?




In the iptables ruleset above, what conntrack state is used to allow replies to outbound connections back through the firewall?




The principle that every user and service should have access to only what it needs — and nothing more — is called what? (two words)



Quiz

What makes a stateful firewall more secure than a stateless one?



Why can an open port 443 still represent a security risk even on a hardened firewall?



What is the most important step to take before running sudo ufw enable on a remote server?


Up Next · Lesson 16

Secure Network Architecture

How to design networks that contain breaches — DMZs, VLANs, network segmentation, and why a flat network is every attacker's favourite environment.