April 7, 2024

Fedora 39 -- restrict ssh to specific subnet

I recently finished a full reinstall of Fedora 39 onto a new hard drive. I am now noticing things like this:
ssh cholla
Last failed login: Fri Apr  5 13:32:20 MST 2024 from 170.64.201.118 on ssh:notty
There were 6 failed login attempts since the last successful login.
Last login: Wed Apr  3 17:22:01 2024 from 72.212.125.20

This is for user "tom", I can only imagine the pounding user "root" is taking.

I could just rely on my good passwords, but I am a believer in multiple layers of security. In the past I had restricted ssh to known subnets (such as the one my off-site machine was assigned by my ISP.) In the past I did this using the old "iptables" scheme. What I want to do now is to learn how to do the same thing using firewalld.

There is a risk in doing this (from my remote machine) and that is that if I screw up, I will have to drive to my office and fix things.

The general idea

Based on the link above:
# add a new zone with a set of allowed source networks
firewall-cmd --permanent --new-zone=ssh-limited

#firewall-cmd --permanent --zone=ssh-limited --add-source=10.20.10.0/24

firewall-cmd --permanent --zone=ssh-limited --remove-source=72.212.125.20
firewall-cmd --permanent --zone=ssh-limited --add-source=72.212.125.20/16
firewall-cmd --permanent --zone=ssh-limited --add-source=72.201.0.0/16
firewall-cmd --permanent --zone=ssh-limited --add-source=128.196.100.19

firewall-cmd --zone=ssh-limited --list-all

# add the SSH service to the created zone
firewall-cmd --permanent --zone=ssh-limited --add-service=ssh

# remove SSH from the default zone (public)
firewall-cmd --permanent --remove-service=ssh

# apply changes by reloading the firewall
firewall-cmd --reload

# list active zones and their configurations
firewall-cmd --get-active-zones
firewall-cmd --list-all
firewall-cmd --zone=ssh-limited --list-all
The old iptables rules had a bunch of lines like this:
-A INPUT -s 128.196.100.19 -m state --state NEW -p tcp --dport 22 -j ACCEPT
-A INPUT -s 72.201.0.0/16  -m state --state NEW -p tcp --dport 22 -j ACCEPT

Try it -- it works, but it doesn't

I did the above, and it seemed to work. At least ssh kept working. However, http stopped working! I see this:
systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
     Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; preset: enabled)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: active (running) since Tue 2024-04-02 12:57:49 MST; 5 days ago
       Docs: man:firewalld(1)
   Main PID: 950 (firewalld)
      Tasks: 4 (limit: 38281)
     Memory: 55.4M
        CPU: 4.990s
     CGroup: /system.slice/firewalld.service
             └─950 /usr/bin/python3 -sP /usr/sbin/firewalld --nofork --nopid

Apr 02 12:57:45 griddle systemd[1]: Starting firewalld.service - firewalld - dynamic firewall daemon...
Apr 02 12:57:49 griddle systemd[1]: Started firewalld.service - firewalld - dynamic firewall daemon.

I see this for the new zone I added:

firewall-cmd --zone=ssh-limited --list-all
ssh-limited (active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces:
  sources: 72.201.0.0/16 128.196.100.19 72.212.125.20/16
  services: ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
And I see this for the default (public) zone:
firewall-cmd --list-all
public (default, active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: eno1
  sources:
  services: dhcpv6-client http mdns
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Dig deeper

We have more zones (set up by Fedora) as follows:
firewall-cmd --get-zones
FedoraServer FedoraWorkstation block dmz drop external home internal nm-shared public ssh-limited trusted work
Also worth noting is that on another system when I went to add the firewall rule for samba, I had to add it to the "FedoraWorkstation" zone -- it did not work to just add it to the default zone as I might have suspected. I had to do this:
firewall-cmd --permanent --zone=FedoraWorkstation --add-service=samba
firewall-cmd --reload
I can use either of these two commands to investigate, the second is more terse.
firewall-cmd --zone=FedoraWorkstation --list-all
firewall-cmd --zone=FedoraWorkstation --list-services
I see this:
dhcpv6-client samba-client ssh
And indeed, if I stop the firewall, my web pages begin working again. Don't forget these commands for general firewall abuse:
systemctl status firewalld
systemctl stop firewalld
systemctl start firewalld
And for general diagnosis:
firewall-cmd --get-zones
firewall-cmd --list-all
firewall-cmd --zone=ssh-limited --list-all

Revert to the original

firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --delete-zone=ssh-limited
firewall-cmd --reload
And now both ssh and http are working again. Very strange.

Closing comments

Two notes --

First, if I had used stop then start, things probably would have worked remotely (I just would have briefly been unprotected by my firewall). But working remotely with some services you would have shot yourself in the foot, for example if you stopped sshd.

Second the command "firewall-cmd --list-all" in its various forms doesn't show anything until you reload firewalld.


Have any comments? Questions? Drop me a line!

Adventures in Computing / tom@mmto.org