2024-04-06 Thinking that even more closing down of SSH attempts could be desirable. Already we have "fail2ban" preventing large numbers of retries from the same addresses or networks. But, given that there's little chance of users needing to access this server from outside Sweden, and they probably can use VPN if they need to, it may be worth being more restrictive. The 'xz' issue of late March 2024 helped remind that the mighty OpenSSH isn't so secure as it could be by itself, when it's linked against other things that link other things. And on this particular computers ('simlin2', RHEL7 [CentOS7]) we're running "thinlinc" server which has its own SSH account accessible by (if I've understood the working correctly) basically anyone with a "private" key that goes in all the clients (publicly available), with security provided by the one binary that this account permits to be run .. even without any public service beyond sshd running, this gives a further potential attack if that binary has a weakness. Tried to use tcpwrappers (hosts.allow, hosts.deny) for the purpose, by making a little script that returns 0 (ok) for internet addresses whose GeoIP lookup country-code matches a list (e.g. just "SE"). Doing this cleanly would need our sshd to support a version of tcpwrappers with "aclexec"; but ours (RedHat 7) doesn't. So, we try a work-around whereby the first connection attempt causes the address to be checked (for country) and written to an allow-list (if the country matches the requirement) and subsequent attempts from that address use the allow-list (since hosts.allow takes the first matching line). The main annoyance of this is that it gives a fail on the first attempt. Note! On RHEL9 (AlmaLinux9) we needed to install "tcp_wrappers" package, from the EPEL repository. This wasn't immediately found (why? because of searching for tcpwr... instead of tcp_wr...?). ==> /etc/hosts.allow <== # # hosts.allow This file contains access rules which are used to # allow or deny connections to network services that # either use the tcp_wrappers library or that have been # started through a tcp_wrappers-enabled xinetd. # # See 'man 5 hosts_options' and 'man 5 hosts_access' # for information on rule syntax. # See 'man tcpd' for information on tcp_wrappers # sshd: 127. sshd: 130.237.0.0/255.255.0.0 sshd: /etc/scripts/allowed-addresses.cache sshd: ALL: spawn ( /etc/scripts/geoip-tcpwrappers-filter %a && echo %a >>/etc/scripts/allowed-addresses.cache ) : deny ==> /etc/hosts.deny <== # # hosts.deny This file contains access rules which are used to # deny connections to network services that either use # the tcp_wrappers library or that have been # started through a tcp_wrappers-enabled xinetd. # # The rules in this file can also be set up in # /etc/hosts.allow with a 'deny' option instead. # # See 'man 5 hosts_options' and 'man 5 hosts_access' # for information on rule syntax. # See 'man tcpd' for information on tcp_wrappers # sshd: ALL ==> /etc/scripts/geoip-tcpwrappers-filter <== #!/usr/bin/env python2 # # RHEL7: yum install python2-geoip2 # also need to copy the downloaded (by MaxMind free-account) GeoLite2 mmdb database to this computer import sys import geoip2.database reader = geoip2.database.Reader('/usr/share/GeoIP/GeoLite2-City.mmdb') if len(sys.argv) != 2 or not sys.argv[1]: print("expected single argument giving internet address") sys.exit(2) response = reader.city(sys.argv[1]) #print( "resp: " + response.country.iso_code + " and " + response.country.names['zh-CN'] ) with open('/etc/scripts/query.log','a') as fout: fout.write(sys.argv[1] + "," + response.country.iso_code + "," + response.country.names['en'] + "\n") allowed = ['SE'] #allowed = ['SE','DK','NO','FI','GB'] #allowed = ['SE','GB'] if response.country.iso_code in allowed: sys.exit(0) sys.exit(1) ==> <==