There are various guides on the web, regarding how to block a whole country, or a group of IP addresses using various firewall methods.
But, what if we need to do the opposite. Allow only one country, and block everyone else.
This may be particularly useful for personal services, like Nextcloud, that you know will only be used by yourself.
Of course, using the same method, it is also possible to allow only a few IP addresses, a city, or just one ISP. All that is needed are the group of IP blocks.
For countries, we can get them from the IPdeny lists. The aggregated files will be more efficient, since they will have less blocks and thus fewer rules.
Since this article uses firewalld, some quick notes on how it works.
firewalld will have one active zone, with some default
# get all active zones $ firewall-cmd --get-active-zones public interfaces: eth0 # list all rules on the public zone $ firewall-cmd --zone=public --list-all public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
The above rules mean, that everyone coming through the interface eth0 will be allowed on the services ssh and dhcpv6-client.
Now back to our goal. We will need to do the following:
- Get the IP address blocks.
- Create a list, and populate it with our addresses.
- Create a new zone, and set the list to it.
- Assign all the needed services to this zone, remove them from the other zones.
# download the country IP blocks wget "https://www.ipdeny.com/ipblocks/data/aggregated/am-aggregated.zone"
Here we create an
ipset with the name
allowlist (could be
anything), and we populate it with the downloaded list.
# create list firewall-cmd --permanent --new-ipset=allowlist \ --type=hash:net --option=family=inet \ --option=hashsize=4096 --option=maxelem=200000 # populate list firewall-cmd --permanent --ipset=allowlist \ --add-entries-from-file=./am-aggregated.zone # we can display the list like this firewall-cmd --ipset=allowlist --get-entries
Then, we create a new zone
allowzone, assign the
allowlist to it,
and enable some services and ports.
# create zone firewall-cmd --permanent --new-zone allowzone # assign the list to the new zone firewall-cmd --permanent --zone=allowzone --add-source=ipset:allowlist # allow services firewall-cmd --permanent --zone=allowzone --add-service ssh firewall-cmd --permanent --zone=allowzone --add-service http firewall-cmd --permanent --zone=allowzone --add-service https
allowzone will only allow the added services for the
allowlist, and no one else.
# check all the rules on the new zone $ firewall-cmd --permanent --zone=allowzone --list-all allowzone (active) target: default icmp-block-inversion: no interfaces: sources: ipset:allowlist services: http https ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
We still need to remove any enabled services from the
otherwise it will keep allowing everyone on eth0.
Up until this point, since we are using the
nothing will be applied until we reload or restart
since we added a new zone, it is not yet dangerous to do so
now. However, once we remove services like ssh from the active public
zone, we may lock ourselves out. So, some common sense care should be
applied here. Maybe start by removing a less dangerous port first.
# remove services from public zone firewall-cmd --permanent --zone=public --remove-service ssh
Finally, reload or restart