Setting up a Firewall — GNUcode.me

Setting up a Firewall

by Joshua Branson — January 23, 2023

So my guix system servers have been running without a firewall. I have decided to actually fix that. Unfortunately, OpenBSD’s pf does not work on linux. It seems like the best packaged firewall for GNU Guix System is currently provided by the netfilter service. Luckily Guix’s default server provides a good basic configuration for enabling ssh access to the machine. That configuration looks like this:

table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;

    # early drop of invalid connections
    ct state invalid drop

    # allow established/related connections
    ct state { established, related } accept

    # allow from loopback
    iifname lo accept

    # allow icmp
    ip protocol icmp accept
    ip6 nexthdr icmpv6 accept

    # allow ssh
    tcp dport ssh accept

    # reject everything else
    reject with icmpx type port-unreachable
  }
  chain forward {
    type filter hook forward priority 0; policy drop;
  }
  chain output {
    type filter hook output priority 0; policy accept;
  }
}

So it looks like I just need to add in policies just after the #allow ssh line.

It seems like the easiest way to test this service out, is to first, guix install nft, then put your configuration into a file. Then load in those firewall rules via sudo nft -f nftables.conf. If those rules end up breaking things, you can revert the firewall to allow everything via sudo nft flush ruleset. You can also list the current ruleset via sudo nft list ruleset. You can also check the syntax in nftables.conf via sudo nft -cf nftable.conf.

Well I had a firewall working fairly well. I tested the firewall rules via sudo nft -f nftables-lamora.conf, and it worked really well. But this scheme code seemed to break everything on the server. Now, I can’t login to lamora and the websites it hosts are not working.

(service nftables-service-type
         (nftables-configuration
          (ruleset
           (mixed-text-file "nftables.conf"
                            "./nftables-lamora.conf"))))

I reached out to linode support, and I am able to boot the machine in a rescue image, which is pretty awesome. From there I might be able to mount the /dev/sda drive such that /gnu/store is set up properly. But I think that is pretty much beyond me. Too much work to get correct. So instead, I shall start from scratch I suppose. :(

What if I had just run,

mount /dev/sda /mnt
chroot /mnt
sudo guix system roll-back

That might have worked. But it also might not have and it might have just taken me longer too.

Looks like I have a small basic guix image lying around that I can tell linode to use. Let’s try that.

Well that caused a kernel panic. That didn’t work. Probably because I told linode to set the root password, and linode doesn’t know how to mess with guix system?

So I whiped my linode server, and started over. And it looks like I need to modify the current cookbook entry about running guix system on linode via adding in

sudo apt-get update, then sudo apt-get install gpg.

Here are some of the commands that I used to set up my new linode server. It's on the same IP address. It's currently hosting gnucode.me.

wget https://notabug.org/jbranso/linode-guix-system-configuration/raw/master/gnucode.me-initial-config.scm
mount /dev/sdc /mnt
sudo guix system reconfigure locke-lamora-initial-config.scm
guix install git
mkdir -p ~/prog/gnu/guix/guix-config/
cd ~/prog/gnu/guix/guix-config/
git clone https://notabug.org/jbranso/linode-guix-system-configuration
cd ../
git clone https://git.sr.ht/~whereiseveryone/guixrus
sudo mkdir -p /srv/www/html

Now I need to git clone my various static websites on the server.

cd /srv/www/html
sudo git clone https://notabug.org/jbranso/gnucode.me.git
sudo git clone https://notabug.org/jbranso/propernaming.git
sudo git clone https://notabug.org/jbranso/gnu-hurd.com.git
sudo mv propernaming propernaming.org

So I believe that I need to chmod the files in /srv/www/html, so that nginx can actually serve them. Unfortunately, I cannot do a sudo chown -R nginx /srv, because my current guix system does not have an nginx user yet. But I believe that I can still reconfigure the system, even if nginx will not be able to serve the html files. After I have reconfigured, then I should be able chown the owner of /srv to nginx. In the end I actually just did a cd /srv; sudo chmod -R o+r * and just made every file readable by everyone. That sort of violates the principle of least privledge, oh well.

Now that I have made some modifications to my gnucode.me-current-config.scm that comments out various certificate files that are not there yet, I can attempt to reconfigure on the server:

cd prog/gnu/guix/guix-config/linode-guix-system-configuration/
sudo guix system reconfigure gnucode.me-current-config.scm

guix system: error: aborting reconfiguration because commit
9fe5b490df83ff32e2e0a604bf636eca48b9e240 of channel 'guix' is not a descendant
of 900d33527c9286a811f064d4bb8f4a9b18d1db0b

Well let’s try this updating everything. And I believe that you need to do a guix pull as root at least once.

su
guix pull;
exit;
guix pull;

Oh yeah, I also need to power down my linode, delete the debian partition, and resize the guix partition to full size.

Now I believe that I cannot reconfigure my server with the current gnucode.me-current-config.scm, because nginx will fail to start because the letsencrypt scripts are not there yet. So I need to modify the nginx bits before I can start the service. I also decided to set up guix deploy on my gnucode.me machine, so that reconfiguring the remote server is faster.

Ok, so I have my current-config for gnucode.me deployed. Geez, guix deploy is sooo super fast! And all you need to do is to set up ssh-agent and customize a deployment list. I set up ssh-agent via my .bash_profile

cat .bash_profile | grep eval -A 1

if [[ -z $DISPLAY ]] && [[ $(tty) = /dev/tty6 ]]; then
    eval `ssh-agent -s`
    ssh-add
    exec dbus-run-session sway
fi

Now all you need to do is customize this:

(list (machine
       (operating-system %system)
       (environment managed-host-environment-type)
       (configuration (machine-ssh-configuration
                       (host-name "45.56.66.20")
                       (system "x86_64-linux")
                       (user "joshua")
                       (identity "~/.ssh/id_rsa")
                       (host-key "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJgL0hBTWmCVGGvNJYa+YS+fEXs89v0GbdkQ+M+LdZlf root@(none)")
                       (port 63355)))))

The port is the ssh port. And the ssh-ed25519 is found on your remote server’s etc/ssh/ssh_host_ed25519_key.pub file.

Now nginx serves my websites via http. Let’s get https working.

sudo /var/lib/certbot/renew-certificates

Alright, now I can set up my config.scm to allow nginx to serve web traffic via https.

Well, can I get a nftables service running now?

At first it seemed that (service nftables-service-type) is apparently good enough to be a decent firewall for my server. Then very quickly I realized that it was a terrible firewall for a server, because it blocked all http and https traffic.

It looks like the arch linux wiki has a decent configuration example for a server:

https://wiki.archlinux.org/title/Nftables#Examples

So I just took the example nftables configuration for a server and used that. The configuration file is here:

https://notabug.org/jbranso/linode-guix-system-configuration/src/master/nftables.scm

Let me know if you see that I did something silly in it, because I probably did.

Bonus paragraph! It took me about 2-4 hours to re-set up my server just the way it was before, except I haven't set up email yet. If you crashed your server lost your backups, how long would it take you to set up you server, just as it was? 2-4 hours is longer than I expected, but I think guix's declarative approach certainly is pretty awesome!