FreeBSD Fundamentals · Module 10 of 14

PF firewall and system security

Build a safe firewall mental model, validate rules before loading them, and combine network controls with account and package hygiene.

Learning objectives

By the end of this module, you should be able to:

  • Understand how PF is enabled deliberately without changing policy during this lab.
  • Validate a PF ruleset offline with pfctl -n before any future load.
  • Use layered security controls rather than relying on one firewall rule.

PF is one of FreeBSD’s firewall choices

PF uses /etc/pf.conf by default when enabled. On a remote host, a bad ruleset can cut off administration, so validation and console recovery planning are mandatory.

Security is layered

Account policy, SSH configuration, package auditing, filesystem permissions, securelevels/capabilities and firewall policy solve different problems.

Worked examples

See the idea in practice.

Validate before load

pfctl -nf /etc/pf.conf
pfctl -sr
pfctl -si
  • -n parses without loading.
  • -sr shows active filter rules.
Hands-on lab

Lab — Validate a conservative PF ruleset offline

Goal: Build and syntax-check a small PF ruleset without enabling PF or replacing the active firewall policy.

Before you start

  • Disposable VM with console recovery available.
  • This lab is parse-only: do not run pfctl -f, pfctl -e, or set pf_enable=YES.
STEP 1

Inspect PF state without changing policy

sysrc pf_enable 2>/dev/null || true
kldstat | grep -w pf || true
ls -l /dev/pf 2>/dev/null || true
# If the PF device is absent, load only the kernel module:
test -c /dev/pf || kldload pf
pfctl -si || true
STEP 2

Create an offline rules file

cat > /tmp/pf.academy.conf <<'EOF'
set skip on lo0

block all
pass out keep state
pass in proto tcp to port 22 keep state
EOF
cat /tmp/pf.academy.conf
STEP 3

Parse without loading

pfctl -nf /tmp/pf.academy.conf
echo "pfctl exit=$?"
pfctl -nvf /tmp/pf.academy.conf
STEP 4

Clean up the temporary rules file

rm -f /tmp/pf.academy.conf

Verify

  • pfctl -nf returns exit status 0 with no syntax error.
  • No pfctl -f or pfctl -e command is used, and the host SSH session remains unaffected.

Expected outcome

  • The PF parser accepts the ruleset while the active firewall policy is left unchanged.

If it fails

  • If validation fails, fix syntax and rerun pfctl -nf; never turn a parse failure into a live firewall experiment.
  • If PF tooling is unavailable, inspect the installed kernel/module state rather than enabling policy blindly.
Real-world connection

Firewall safety means separating syntax validation from activation and always preserving a management recovery path.

Avoid these traps

Common mistakes

  • Enabling PF on a remote machine before validating SSH reachability.
  • Assuming a firewall replaces service hardening and patching.
Knowledge check

Can you explain it without looking back?

Open each answer only after you have tried to answer the question yourself.

1Which command syntax-checks a PF file without loading it?

pfctl -nf /path/to/pf.conf.

2Where is the default PF ruleset path?

/etc/pf.conf.

3Why keep console recovery during firewall changes?

A ruleset mistake can immediately block remote management.

My Learning

Record your progress for this module.

Progress is saved in this browser immediately. When you sign in to My Learning, it can also sync across devices.

Not started

Attempt the core lab and knowledge checks before marking the module complete.