Header RSS Feed
If you only want to see the articles of a certain category, please click on the desired category below:
ALL Android Backup BSD Database Hacks Hardware Internet Linux Mail MySQL Monitoring Network Personal PHP Proxy Shell Solaris Unix Virtualization VMware Windows Wyse

Allow SSH access based on GeoIP country
Thursday - Nov 3rd 2016 - by - (2 comments)

For a certain online infrastructure there's a SSH jump host in place so that admins, developers and also some external users involved in projects are allowed to connect to the servers.

Of course only key authentication works and we also limited the source ip addresses to the ranges of certain internet providers. But this turned out to be a constant bugger. Either suddenly some new ranges appeared or sometimes a developer has changed his internet provider and the firewall rule needed to be changed again.

Because I know that people involved in this environment only work from a few countries, why not use an access filter based on GeoIP?

Whenever a connection comes in to the SSH daemon, the IP address' origin should be determined by a GeoIP lookup. Depending on which countries are defined as "allowed", they should be allowed to connect.
And this is how it's done (source: https://www.axllent.org/docs/view/ssh-geoip/) on an Ubuntu server (in my case Ubuntu 14.04).

First install the necessary geoip packages:

apt-get install geoip-database geoip-bin

Then create the GeoIP lookup script, which will be launched whenever a new SSH connection is opened. I created it as /usr/local/bin/ipfilter.sh:

# License: WTFPL

# UPPERCASE space-separated country codes to ACCEPT

if [ $# -ne 1 ]; then
  echo "Usage:  `basename $0` " 1>&2
  exit 0 # return true in case of config issue

if [[ "`echo $1 | grep ':'`" != "" ]] ; then
  COUNTRY=`/usr/bin/geoiplookup6 "$1" | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`
  COUNTRY=`/usr/bin/geoiplookup "$1" | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`

if [[ "$RESPONSE" == "ALLOW" ]] ; then
  logger -p $LOGDENY_FACILITY "$RESPONSE sshd connection from $1 ($COUNTRY)"
  exit 0
  logger -p $LOGDENY_FACILITY "$RESPONSE sshd connection from $1 ($COUNTRY)"
  exit 1

Make the script executable:

# chmod 755 /usr/local/bin/ipfilter.sh

In /etc/hosts.deny set all connections to sshd to DENY:

# cat /etc/hosts.deny | grep sshd
sshd: ALL

In /etc/hosts.allow define the GeoIP lookup script created before for all connections to sshd:

# cat /etc/hosts.allow | grep sshd
sshd: ALL: aclexec /usr/local/bin/ipfilter.sh %a

You probably already guessed it correctly. The variable %a represents the incoming IP address, which is then forwarded to the lookup script. The lookup script then makes the GeoIP lookup with the given IP address. If the country code is in the list of allowed countries (ALLOW_COUNTRIES) or is an unknown source the script will exit 0 (OK) and therefore the connection will be allowed. If the country isn't in the allowed list, the script will exit 1 (NOT OK) and that's the signal to the system to drop the connection.

Let's try to make an ssh connection from a host in Germany:

$ ssh claudio@jumphost.example
ssh_exchange_identification: Connection closed by remote host

On the jump host itself the following log entries appear:

Nov  3 12:17:14 jumphost logger: DENY sshd connection from (DE)
Nov  3 12:17:14 jumphost sshd[11345]: aclexec returned 1
Nov  3 12:17:14 jumphost sshd[11345]: refused connect from (

Note: If you're using a RHEL based distribution (for example CentOS), the command "aclexec" doesn't seem to work (see http://tecadmin.net/allow-server-access-based-on-country).
In this case use "spawn" instead of "aclexec" in hosts.allow:

root@rhel # cat /etc/hosts.allow | grep sshd
sshd: ALL: spawn /usr/local/bin/ipfilter.sh %a

On the other hand spawn didn't work on my Ubuntu jump host - here only aclexec really blocked the access.

Of course this is not to be considered as a high security setting. The source IP address can be spoofed to whatever you like. So make sure you have your ssh daemon up to date and harden your settings, for example the typical ones:

  • PasswordAuthentication no
  • PermitRootLogin no
  • AllowUsers (list of allowed users)


Add a comment

Show form to leave a comment

Comments (newest first):

Bella from USA wrote on Jan 3rd, 2018:
Nice work dude.

David from USA wrote on Dec 2nd, 2017:
Great and nice.

Go to Homepage home
Linux Howtos how to's
Monitoring Plugins monitoring plugins
Links links

Valid HTML 4.01 Transitional
Valid CSS!
[Valid RSS]

7213 Days
until Death of Computers