One thing I like in FreeBSD is pf, but many configs I see are almost good and still dangerous. Usually not because pf is bad. It is because admin forget small details.
First one: pf is last match, unless you use quick.
This looks ok to some people:
block all
pass in on $wan proto tcp to port 22
block in on $wan
But the later block can still win. If you really mean "this rule decides now", use quick:
block all
pass in quick on $wan proto tcp from <admin_hosts> to ($wan) port 22 flags S/SA keep state
Then:
table <admin_hosts> persist { 203.0.113.10 }
I prefer table even with one IP, because later you add another admin IP without rewrite the rule. Also to ($wan) is better than hard coded address if interface use DHCP. The parenthesis tell pf to use the current address on that interface.
Second mistake: people make extra inbound rules for replies. Usually you do not need this:
pass in on $wan proto tcp from any to any
If you have:
pass out on $wan keep state
then replies come back by the state table. Check it with:
pfctl -ss
Opening wide inbound "for return traffic" is how many home firewalls become not really firewall.
Third: NAT and filter are different thinking. Keep NAT simple:
nat on $wan from $lan_net to any -> ($wan)
Then make separate rules for what LAN can really do:
pass in quick on $lan from $lan_net to any keep state
pass out quick on $wan keep state
For FreeBSD boot config, I normally want explicit lines in /etc/rc.conf:
pf_enable="YES"
pf_rules="/etc/pf.conf"
pflog_enable="YES"
And before reload, always parse test:
pfctl -nf /etc/pf.conf
If no error, reload:
pfctl -f /etc/pf.conf
Then look what is really loaded:
pfctl -sr
pfctl -sn
pfctl -ss
pfctl -sr is important. The firewall in your head and the firewall loaded in kernel are not always same thing.
pf is exact tool. Small rule order problem, missing quick, too broad pass, or not checking states can change the whole security. This is why I like to keep rules simple and readable, not clever.
BSDSábio
"menos hype, mais dmesg"