Basic Linux server firewall

Somehow I never feel that my servers are protected well enough and probably they actually never will be 🙂

Those are the firewall rules I use on most systems. They basically want to accomplish the following:

  • allow only defined incoming ports, deny all others
  • define trusted networks which are allowed for all traffic
  • allow certain ports only to be reachable from a certain country
    • e.g. ssh (tcp/22) or imap (tcp/993) only from Germany but
    • submission (tcp/587) and smtp (tcp/25) from everywhere

As a firewall I use nftables on a Debian server. In order to define countries I use a script to define according sets for the firewall. There are two solutions for this GeoIP integration with nftables – I don’t use the one mentioned on the notables Wiki page as it’s pretty old and slows down notables a lot (it’s also mentioned as as an actual problem in the Wiki)!!!

So basically you need nftables (https://wiki.nftables.org) and optionally geoipsets (https://github.com/chr0mag/geoipsets) for country based rules. Just follow the instructions to create the required definitions of countries and their ipV(4,6) networks. I put the files created all under /etc/nftables/geopisets/ directory.

!!! Warning: This configuation is just to give an idea – don’t use without prior tests !!!

It’s usually a good idea to disable the service for notables so in case you lock yourself out a reboot helps… Once you feel confident just enable the service again for automatic startup after a re-boot.

# to disable the systemd service
systemctl disable nftables

# enable the systemd service again once you feel confident!!!
systemctl enable nftables

As a pretty simple admin I put the configuration in the /etc/nftables.conf :

#!/usr/sbin/nft -f

# let's remove allwe have so far and start from scratch 
flush ruleset

# define trusted networks (e.g. home networks)
define IP4_HOME = { 80.70.60.50, 192.168.1.0/24 }
define IP6_HOME = { 2a01:9876:543:1234::/64, 2a01:9876:543:1235::/64 }
 
table inet filter {

  # as I just want to check for DE, that's all I need
  include "/etc/nftables/geoipsets/*"
  set country-v4-de {
        type ipv4_addr
        flags interval
        elements = $DE.ipv4
  }
  set country-v6-de {
        type ipv6_addr
        flags interval
        elements = { $DE.ipv6 }
  }

  # whatever is not defined here will be DROPed
  chain input {
    type filter hook input priority 0; policy drop;

    # allow all traffic from well known networks 
    iifname lo accept
    ip  saddr $IP4_HOME ct state new,established,related accept
    ip6 saddr $IP6_HOME ct state new,established,related accept
 
    # allow servers from DE to use imap and ssh
    ip  saddr @country-v4-de tcp dport { ssh, imaps } ct state new,established,related accept
    ip6 saddr @country-v6-de tcp dport { ssh, imaps } ct state new,established,related accept

    # those are the services everyone should be able to access
    tcp dport { http, https, submission, submissions, smtp } ct state new,established,related accept

    # allow for DHCP traffic to be working
    udp sport 67 udp dport 68 counter accept
    udp sport 68 udp dport 67 counter accept
    udp sport 546 udp dport 547 counter accept
    udp sport 547 udp dport 546 counter accept

    # accepting ping (icmp-echo-request) for diagnostic purposes.
    icmp type echo-request limit rate 5/second accept 
    # accept neighbour discovery otherwise connectivity breaks
    icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
    icmpv6 type echo-request limit rate 5/second accept

    # this line is really(!!!) important initaited outgoing traffic working
    ct state established,related accept

    # log all dropped packets
    log prefix "NFT DROP: " flags all counter
  }


  chain forward {
    type filter hook forward priority 0;
  }


  chain output {
    type filter hook output priority 0; policy accept;
  }


}

This is a pretty basic ruleset but can be used as a base for a much better firewall. If you also use Crowdsec on top of this basic firewall your server is already pretty safe. Changing the default ssh port and replacing the default ssh port with a honeypot put the cream on top 🙂

Happy watching all blocked connections showing up in your logs!!!