Secure FreeNAS 9.2.1.2 with a Firewall

The recent NTP reflection incident I was a victim of woke me up to the need for securing my FreeNAS boxes from outside connections.  Luckily, FreeNAS 9.2.1.2 comes shipped with the kernel extension for pf, so getting it working is pretty easy.

If you are going to do this on your FreeNAS box, please also check out my guide on getting hacks to FreeNAS to survive system upgrades.

DISCLAIMER – I AM NOT A SECURITY EXPERT, FOLLOW THIS GUIDE AT YOUR OWN RISK

I’ve been told that pf does not play nice with vimage jails.  It tends to cause kernel panics.

Get the basics done

1. Mount the filesystem so we can make some changes.

su
enter your root password
mount -uw /

2. Figure out what interfaces you have active so we can add them to the firewall rules.

ifconfig

Your output should look something like this:

re0: flags=8943<up,broadcast,running,promisc,simplex,multicast> metric 0 mtu 1500
options=82099<RXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE>
ether f4:6d:04:db:21:ba
inet 192.168.0.10 netmask 0xffffff00 broadcast 192.168.0.255
inet6 xxxx::xxxx:xxxx:xxxx:xxxx%re0 prefixlen 64 scopeid 0x6
inet xxx.xxx.xxx.xxx netmask 0xfffffff8 broadcast 50.241.46.71
nd6 options=23<performnud,accept_rtadv,auto_linklocal>
media: Ethernet autoselect (1000baseT )
status: active

ipfw0: flags=8801<up,simplex,multicast> metric 0 mtu 65536
nd6 options=9<performnud,ifdisabled>

lo0: flags=8049<up,loopback,running,multicast> metric 0 mtu 16384
options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0xa
inet 127.0.0.1 netmask 0xff000000
nd6 options=21<performnud,auto_linklocal>

bridge0: flags=8843<up,broadcast,running,simplex,multicast> metric 0 mtu 1500
ether 02:df:7f:1c:ff:00
nd6 options=1
id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200
root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
member: epair0a flags=143<learning,discover,autoedge,autoptp>
ifmaxaddr 0 port 12 priority 128 path cost 2000
member: re0 flags=143<learning,discover,autoedge,autoptp>
ifmaxaddr 0 port 6 priority 128 path cost 20000

epair0a: flags=8943<up,broadcast,running,promisc,simplex,multicast> metric 0 mtu 1500
options=8<VLAN_MTU>
ether 02:09:09:00:0c:0a
nd6 options=1
media: Ethernet 10Gbase-T (10Gbase-T )
status: active

tun0: flags=8051<up,pointopoint,running,multicast> metric 0 mtu 1500
options=80000<LINKSTATE>
inet 10.8.0.1 –> 10.8.0.2 netmask 0xffffffff nd6 options=1
Opened by PID 17528

What we want to note are all the interface names.  Mine are re0, ipfw0, lo0, bridge0, epair0a and tun0

Create the firewall rules

3. Create the pf.conf file and edit it to your needs.  We are going to put it on our data drive so future FreeNAS upgrades don’t wipe it out. Adjust the path to match your setup.

mkdir /mnt/Files/hacks
vi /mnt/Files/hacks/pf.conf

Side note, vi has lots of commands, we just need to know a few:

x will delete the character your cursor is over, i will insert, esc will exit insert mode and to save and quit we use :wq

Here are the rules I am running.

#change this to match your primary ethernet interface, re0 or em0 are common, but there are others
ext_if="re0"
vpn_if="tun0"
table <bruteforce> persist
#These are all of the other interfaces we discovered in step 2
set skip on lo0
set skip on bridge0
set skip on ipfw0
set skip on epair0a
set skip on tun0
set block-policy return
scrub in all
#change xxx.xxx.xxx.xxx to the external IP of your FreeNAS box
nat on $ext_if from 10.8.0.0/24 to any -> xxx.xxx.xxx.xxx
#Lock it down
block in all
block out all
#Allow VPN traffic
pass on tun0 keep state
block quick from <bruteforce>
#Allow traffic in for ssh
pass in on $ext_if proto tcp from any to any port 22 flags S/SA keep state (max-src-conn 10, max-src-conn-rate 5/5, overload <bruteforce> flush global)
#Allow traffic in for web - delete or comment out if you don't want web traffic
pass in on $ext_if proto tcp from any to any port 80 flags S/SA keep state
pass in on $ext_if proto tcp from any to any port 443 flags S/SA keep state
#Allow traffic in for OpenVPN
pass in on $ext_if proto udp from any to any port 1194 keep state label "openvpn"
#Allow LAN traffic to connect to FreeNAS - change xxx.xxx.xxx.0 to match your network, ie 192.168.0.0 or 10.0.0.0
pass in on $ext_if from xxx.xxx.xxx.0/24 to any keep state
#Allow traffic out from the LAN
pass out on $ext_if from any to any keep state

Enable the Firewall

4. Edit /etc/rc.conf and add the following.

vi /etc/rc.conf

pf_enable="YES"
pf_rules="/mnt/Files/hacks/pf.conf"
gateway_enable="YES"

5. Start up the firewall and see if it works

service pf start

Your should get this as your output:

Enabling pf
No ALTQ support in kernel
ALTQ related functions disabled

Now check to make sure it is working:

service pf status

Your output should be something like this:

No ALTQ support in kernel
ALTQ related functions disabled
Status: Enabled for 0 days 00:04:55           Debug: Urgent

State Table                          Total             Rate
current entries                       29
searches                         1040038         3525.6/s
inserts                               95            0.3/s
removals                             109            0.4/s
Counters
match                               1093            3.7/s
bad-offset                             0            0.0/s
fragment                               0            0.0/s
short                                  0            0.0/s
normalize                              0            0.0/s
memory                                 0            0.0/s
bad-timestamp                          0            0.0/s
congestion                             0            0.0/s
ip-option                             22            0.1/s
proto-cksum                            0            0.0/s
state-mismatch                         0            0.0/s
state-insert                           0            0.0/s
state-limit                            0            0.0/s
src-limit                              0            0.0/s
synproxy                               0            0.0/s

6. Start IP Forwarding without restarting your server

sysctl net.inet.ip.forwarding=1

Then make sure to go into the FreeNAS gui, click on System, Click on Sysctls.  Then add that same value so it survives reboots.

Screen Shot 2014-05-14 at 10.43.22 AM

Make your changes stick

7.  Add your rc.conf changes to /conf/base/etc/rc.conf

vi /conf/base/etc/rc.conf

pf_enable="YES"
pf_rules="/mnt/Files/hacks/pf.conf"
gateway_enable="YES"

To really make these changes stick, follow my guide on the subject.

Clean Up

8. Make the filesystem read only again

mount -ur /

Final Thoughts

An added benefit of setting up a firewall this way is that it will let you route to other computers on your LAN over your VPN.  Hope you all enjoy this and let me know how things work out for you.

Advertisements

42 thoughts on “Secure FreeNAS 9.2.1.2 with a Firewall

  1. Pingback: OpenVPN on FreeNas 9.1 | The Joe Paetzel Method

      • #change this to match your primary ethernet interface, re0 or em0 are common, but there are others
        ext_if=”em0″
        vpn_if=”tun0″
        #These are all of the other interfaces we discovered in step 2
        set skip on re0
        set skip on lo0
        set skip on bridge0
        set skip on ipfw0
        set skip on epair0a
        set skip on epair1a
        set skip on epair2a
        set skip on epair3a
        set skip on epair4a
        set skip on epair5a
        set skip on tun0
        set block-policy return
        scrub in all
        #change xxx.xxx.xxx.xxx to the external IP of your FreeNAS box
        nat on $ext_if from 10.8.0.0/24 to any -> 192.168.1.8
        #Lock it down
        block in all
        block out all
        #Allow VPN traffic
        pass on tun0 keep state
        block quick from
        #Allow traffic in for ssh
        pass in on $ext_if proto tcp from any to any port 22 flags S/SA keep state
        #Allow traffic in for web – delete or comment out if you don’t want web traffic
        pass in on $ext_if proto tcp from any to any port 80 flags S/SA keep state
        pass in on $ext_if proto tcp from any to any port 443 flags S/SA keep state
        #Allow traffic in for OpenVPN
        pass in on $ext_if proto udp from any to any port 1194 keep state label “openvpn”
        #Allow LAN traffic to connect to FreeNAS – change xxx.xxx.xxx.0 to match your network, ie 192.168.0.0 or 10.0.0.0
        pass in on $ext_if from 192.168.1.0/24 to any keep state
        #Allow traffic out from the LAN
        pass out on $ext_if from any to any keep state

      • Ok the syntax error was pointing at the line that has the brute force info. Once I deleted it, the error went away. Is there in an error above?

  2. Yes, there was an error. WordPress decided not to “print” the parts. It should be this…I fixed it above:

    table <bruteforce> persist

    block quick from <bruteforce>

    Thanks for catching this!!!

      • Yes…darn wordpress. Fixed it above…should be this:

        pass in on $ext_if proto tcp from any to any port 22 flags S/SA keep state (max-src-conn 10, max-src-conn-rate 5/5, overload <bruteforce> flush global)

  3. Hi Joe!
    First off, thank you for your OpenVPN tutorials. They have been extremely informative and well written, thank you for taking the time to make them. I couldn’t imagine setting up my system without them.
    However, like most posters I imagine, I’m here because I encountered problems and I lack the technical expertise to fix them on my own. I’ve followed your guide as closely as possible but I’ve failed to successfully implement the packet filter. It runs and I have no issue with internet access from the VPN client device but I’m unable to reach devices on the local lan. When checking the pf status I see zero movement of packets! Is this because the lan is behind a router?
    Thanks again! 🙂

    • Hi Tristan –
      I really appreciate the kind words regarding the guides!

      So help me understand. Is the FreeNAS box behind the same router? What type of port forwarding are you doing on the router? Could you email me your output from ifcong , and your pf.conf file? You can use the email form on the about page. Might as well include the openvpn server config file. Feel free to xxx.xxx.xxx.xxx out the ip’s.

      • Done! Thanks Joe, it’s really appreciated. I’m looking forward to hearing back from you!

  4. A superb guide! I had been struggling with getting this done for ages and it worked flawlessly.

    A small tip in case you would like to route all your traffic over the VPN server once connected, including that to the internet is to add these 2 lines to your openvpn.conf file:

    push “redirect-gateway def1”
    push “dhcp-option DNS 8.8.8.8”

    Chose your own DNS server by all means, this is a Google one.

  5. Hi Joe,
    First of all, great tutorial 🙂
    I’ve followed the OpenVPN one, and then i wanted to configure some firewall rules.
    I’ve followed all of the tutorial,yet the openVPN port is still CLOSED from outside.

    Have you any idea why it’s happening ?
    Thanks in advance,
    Regards,
    Bastien DINE

  6. Hi Joe, I have a question.

    I followed your guide and everything goes smoothly but when I reboot my FreeNAS I cannot access to my Plugins, I need to stop pf and start again, and then everything works.
    Do you know why this is happening?
    Maybe it’s a hardware issue?
    It’s like the system needs to load first the interfaces for each plugin and then start the firewall.

    Thanks for all your blog 🙂

  7. Question about:

    “change xxx.xxx.xxx.xxx to the external IP of your FreeNAS box”

    Is that referring to the LAN IP it’s getting from the router, or referring to actual external IP (WAN)?

    • If you are passing an IP through then it is the public IP for the FreeNAS box. If you are forwarding a port on the router, then it is the LAN IP for FreeNAS. If you are forwarding the port, then on the client config, be sure to use the public IP of your router.

    • Hmmm, just realized which post you were commenting on. My answer probably didn’t make a lot of sense. I had assumed if you are setting up a firewall, that you have a public IP assigned to your FreeNAS box. I guess it would probably work without one. So yeah, you should be able to use an internal IP. Long story short, it needs to be an IP on the FreeNAS box.

      • Thanks =] Your first reply answered it, I am forwarding 1194 within OpenWRT to the LAN IP and have the server.conf setup to use the ddns host name for the WAN IP

    • (As a heads up, I just recently delved into UNIX based OSes and am learning as I go)
      Also, i wanted to understand what each command meant, so I looked at the rule syntax page, and according to the description of pf (link below), it states:

      “Filter rules are evaluated in sequential order, first to last. Unless the packet matches a rule containing the quick keyword, the packet will be evaluated against all filter rules before the final action is taken. The last rule to match is the “winner” and will dictate what action to take on the packet.”

      I take this to mean that it starts at the top of script and works it way down, so does this mean the default of deny all should be at the bottom of the script instead of the top? Thanks =]

  8. I have a server board with 2 LANS and an IPMI LAN… can I simply add the additional LAN on the next line below the first, such as:

    ext_if=”igb0″
    ext_if=”igb1″
    vpn_if=”tun0″
    vpn_net='”10.8.0.0/24″‘
    table persist

    • Nope. I don’t think so. ext_if is a variable, so by defining it twice, my guess is, only the last setting would stay. So in your example, ext_if = igb1

      Not sure if you can define multiple interfaces with commas. I’d say, just use ext_if and ext2_if.

      Are all three NIC’s being used? You probably only need to set up one of them for your standard rules and then the IPMP NIC you’d want separate rules for anyway.

  9. int_if=”em0″
    localnet = $int_if:network
    pass in on $int_if from $localnet to any keep state

    now no need to edit to match your network

  10. Thank you for this wonderfull tutorial – again 🙂

    One error has been bugging me for an houre, maybe because I am some kind of noob.

    Whenever I fired the pf up I got an error message on the last line of the pf.conf file, no matter what it contains.

    I turns out that I edited the conf-file with Adobe Dreamweaver and had to add an extra empty line at the end of the file.

    Maybe you can right it as an additional info for someone like me who has the same
    problems.

  11. Pingback: Configurando packet filtering en FreeNAS 9.3 | Tutoriales CECT

  12. Hey, thank you very much for this!
    I found this, because I was wondering, if it can be used to make the built-in TFTP-server a little bit more secure. I only need TFTP availably for a certain IP range in the network (like 10.0.0.20 – 10.0.0.30). In this range IP-Phones reside and should be able to load their config files – no other network client outside of the range should be able to do this.
    Is it possible to adapt the code for this application?
    Thanks a lot for your help and have a Merry Christmas!

    • Hi Michael-
      I have not played with FreeNAS for a very long time. All of the custom stuff I did was on now, very old versions. I have no way of knowing if this will work on a current version of FreeNAS. All that said,
      you should be able to do that. TFTP runs on port 69 by default. To specify a range of IP’s you just use a hyphen, so 10.0.0.20 – 10.0.0.30 .

      So something like this might work:
      #Allow traffic in from phones for TFTP
      pass in on $ext_if from 10.0.0.20 – 10.0.0.30 to any port 69 flags S/SA keep state (max-src-conn 10, max-src-conn-rate 5/5, overload flush global)

      Again, I’m no expert and do not know if any of my posts work at all with more recent versions of FreeNAS.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s