How to Secure FreeBSD with PF Firewall

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 VCCLHOSTING 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 zfs 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:

<vultr>[~]$ su
Password:
<vultr>[~]# passwd 
Changing local password for root
New Password:
Retype New Password:
<vultr>[~]# 

We don't need sendmail. Stop and disable this service:

<vultr>[~]# /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 Vultr 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 Vultr).

# ---- 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!

  • 34 Users Found This Useful
Was this answer helpful?

Also Read

Access Single User Mode (Reset Root Password)

To reset the root password of your server, you will need to boot into single user mode. Access...

Port 25 unblock

Port 25 in VCCLHOSTING  is blocked by default. If you need to send out email , you can follow...

How to Create, Deploy and Launch Virtual Machines in OpenStack

Step 1: Allocate Floating IP to OpenStack 1. Before you deploy an OpenStack image, first you...

Configuring IPv6 on your VPS

All these examples assume an IPv6 subnet of 2001:DB8:1000::/64. You'll need to update them with...

Reset Windows Server Administrator Password

There are times when you have forgotten your local administrator password on Windows and need to...