This tutorial will show you how to protect your FreeBSD server using OpenBSD PF firewall. We will assume that you have a clean FreeBSD installation deployed by AKLWEB Host with no users added. We will do some other things beside Firewall configuration which will also harden the security of our FreeBSD server. Before firewall configuration, we will install some packages since the default FreeBSD installation comes with a minimal set of tools and packages (which is correct), to make it easier for us to work.
The default shell in FreeBSD is /bin/sh
. This is a basic shell with no auto-complete functions. We will use something better. We will install zsh
.
First, install these packages:
# pkg install zsh gnuls
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/freebsd:10:x86:64/latest, please wait...
...
GNULS is the ls
program from Linux. We just want to have the same ls
command in Linux and FreeBSD.
Add a normal user to the system: (replace john with your username and don’t forget to add user to the wheel group)
# adduser
Username: john
Full name: John Doe
Uid (Leave empty for default):
Login group [john]:
Login group is john. Invite john into other groups? []: wheel
Login class [default]:
Shell (sh csh tcsh zsh rzsh nologin) [sh]: zsh
Home directory [/home/john]:
Home directory permissions (Leave empty for default):
Use password-based authentication? [yes]:
Use an empty password? (yes/no) [no]:
Use a random password? (yes/no) [no]:
Enter password:
Enter password again:
Lock out the account after creation? [no]:
Username : john
Password : *****
Full Name : John Doe
Uid : 1001
Class :
Groups : john wheel
Home : /home/john
Home Mode :
Shell : /usr/local/bin/zsh
Locked : no
OK? (yes/no): yes
adduser: INFO: Successfully added (john) to the user database.
Add another user? (yes/no): no
Goodbye!
Create zsh config file:
# ee /home/your-username/.zshrc
Copy this to your .zshrc file:
PS1="<%U%m%u>$[%B%1~%b]%(#.#.$) "
bindkey -e
alias su='su -m'
alias du='du -h -d0'
alias df='df -h'
alias l=less
alias ll='gnuls --color=always -l'
alias ls='gnuls --color=always'
alias pkg_ver='pkg version -v -l "<" | > upgrade'
export EDITOR=ee
autoload -U colors && colors
autoload -U promptinit && promptinit
autoload -U compinit && compinit
# History settings
SAVEHIST=1000
HISTSIZE=1000
HISTFILE=~/.history
setopt histignoredups appendhistory
Run this command: (replace john with your username)
chown john:john /home/john/.zshrc
Now, login to the FreeBSD server with your username and change the default root password:
<aklwebhost>[~]$ su
Password:
<aklwebhost>[~]# passwd
Changing local password for root
New Password:
Retype New Password:
<aklwebhost>[~]#
We don’t need sendmail. Stop and disable this service:
<aklwebhost>[~]# /etc/rc.d/sendmail stop
Stopping sendmail.
Waiting for PIDS: 7843.
sendmail_submit not running? (check /var/run/sendmail.pid).
Stopping sendmail_msp_queue.
Waiting for PIDS: 7846.
Next, we will change our rc.conf file to look more natural:
# ee /etc/rc.conf
Change it to look like this:
#----------- NETWORKING ------------------------------------------------#
hostname="ceph.domain1.com" # replace ceph.domain1.com with your domain
ifconfig_vtnet0="dhcp"
static_routes=linklocal
route_linklocal="-net 169.254.0.0/16 -interface vtnet0"
#--------- SERVICES BSD LOCAL ----------------------------------------#
sshd_enable="YES"
ntpd_enable="YES"
#pf_enable="YES"
#pf_rules="/etc/firewall"
#pf_flags=""
#pflog_enable="YES"
#pflog_logfile="/var/log/pflog"
#pflog_flags=""
sendmail_enable="NONE"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
Edit /etc/hosts
file:
# ee /etc/hosts
Add your IP address and hostname:
::1 localhost localhost.ceph ceph
127.0.0.1 localhost localhost.ceph ceph
108.61.178.110 ceph.domain1.com ceph
Set timezone:
# bsdconfig
Whenever you can, disable remote access for the root user. Most attacks on SSH will try to access through the root user account. Always connect with your username and then su
to root. Only users from the wheel
group can su
to root. That’s why we added our user to the wheel group.
Disable root login:
# ee /etc/ssh/sshd_config
Uncomment this line:
PermitRootLogin no
Reboot:
# reboot
After the reboot finishes, you will see a message like this in the AKWLEB Host console:
time correction of 3600 seconds exceeds sanity limit (1000); set clock manually to
correct UTC time.
That’s why we need to correct the clock manually. Follow these commands, first su
to root:
$ su
Password:
# ntpdate 0.europe.pool.ntp.org
Now, we are going to configure the firewall. OpenBSD PF is included in the FreeBSD kernel, so you don’t have to install any packages.
With ee
editor, create file /etc/firewall
:
# ee /etc/firewall
Insert this: (replace any IP addresses with yours)
#######################################################################
me="vtnet0"
table <bruteforcers> persist
table <trusted> persist file "/etc/trusted"
icmp_types = "echoreq"
junk_ports="{ 135,137,138,139,445,68,67,3222 }"
junk_ip="224.0.0.0/4"
set loginterface vtnet0
scrub on vtnet0 reassemble tcp no-df random-id
# ---- First rule obligatory "Pass all on loopback"
pass quick on lo0 all
# ---- Block junk logs
block quick proto { tcp, udp } from any to $junk_ip
block quick proto { tcp, udp } from any to any port $junk_ports
# ---- Second rule "Block all in and pass all out"
block in log all
pass out all keep state
############### FIREWALL ###############################################
# ---- Allow all traffic from my Home
pass quick proto {tcp, udp} from 1.2.3.4 to $me keep state
# ---- block SMTP out
block quick proto tcp from $me to any port 25
# ---- Allow incoming Web traffic
pass quick proto tcp from any to $me port { 80, 443 } flags S/SA keep state
# ---- Allow my team member SSH access
pass quick proto tcp from 1.2.3.5 to $me port ssh flags S/SA keep state
# ---- Block bruteforcers
block log quick from <bruteforcers>
# ---- Allow SSH from trusted sources, but block bruteforcers
pass quick proto tcp from <trusted> to $me port ssh \
flags S/SA keep state \
(max-src-conn 10, max-src-conn-rate 20/60, \
overload <bruteforcers> flush global)
# ---- Allow ICMP
pass in inet proto icmp all icmp-type $icmp_types keep state
pass out inet proto icmp all icmp-type $icmp_types keep state
Create /etc/trusted
file. In this file, we will put IPs that we “trust”.
# ee /etc/trusted
Add some IP’s:
# Hosting
1.2.0.0/16
# My friends
1.2.4.0/24
Now some explanation. Junk ports and junk IPs are just some ports/IPs that we don’t want to see in logs. We have done this with this rule:
# ---- Block junk logs
block quick proto { tcp, udp } from any to $junk_ip
block quick proto { tcp, udp } from any to any port $junk_ports
These are just defaults and you don’t have to worry about it:
icmp_types = "echoreq"
set loginterface vtnet0
scrub on vtnet0 reassemble tcp no-df random-id
pass quick on lo0 all
block in log all
pass out all keep state
This rule blocks outgoing SMTP traffic from your server (which is the default on AKLWEB Host).
# ---- block SMTP out
block quick proto tcp from $me to any port 25
Except bruteforcers
the rest is pretty straight forward.
# ---- Allow SSH from trusted sources, but block bruteforcers
pass quick proto tcp from <trusted> to $me port ssh \
flags S/SA keep state \
(max-src-conn 10, max-src-conn-rate 20/60, \
overload <bruteforcers> flush global)
Bruteforcers just says: Allow from <trusted> IPs to port 22 but only 10 concurrent connections can be made from one source IP. If it’s more than 10, block this IP and put it in table bruteforcers. The same goes for 20/60 rule. It means a max of 20 connections in 60 seconds.
Enable firewall:
# ee /etc/rc.conf
Uncomment these lines:
pf_enable="YES"
pf_rules="/etc/firewall"
pf_flags=""
pflog_enable="YES"
pflog_logfile="/var/log/pflog"
pflog_flags=""
Reboot:
# reboot
If you have done everything right, then you will be able to login and the firewall will be enabled. You don’t have to reboot every time you change the /etc/firewall
file. Just do:
# /etc/rc.d/pf reload
See who is trying to connect to your server in real-time:
# tcpdump -n -e -ttt -i pflog0
Show history:
# tcpdump -n -e -ttt -r /var/log/pflog
See if you have someone in bruteforcers table:
# pfctl -t bruteforcers -T show
And that’s it. You have successfully implemented PF firewall on FreeBSD server!