Background:
I have a few Amazon Linux 2 EC2 instances that I run for personal use. Generally, I restrict "important" / remote access services to my home egress IPs, but for services that I expect to be generally available I cannot do that.
Anyone who has hosted a service on the public Internet knows that it's a matter of minutes after the service comes online before it starts being probed by all manner of scanners, exploit scripts, curious hackers, botnets, &etc. No big deal, just build secure services, right?
Naturally. But "defense in depth" dictates that if you can filter out a large percentage of these requests, you should. As doing so not only reduces the load on your service, but also reduces the likelihood of your service being tagged by some unforeseen exploit.
Enter: Maxmind's GeoIP database and the xtables-addons GeoIP filter. With the geoip module you can easily use iptables to restrict traffic to only those countries you know your service will be accessed from. Useful if you're building, say, a game server or similar for only a small group of friends and you know where they all are!
Note: I'm mostly documenting this so that I can repeat it again later without having to rediscover the dependencies / steps. No warranties, support, or promises. You are responsible for your own systems. But I thought someone else might find it useful.
Prerequisites:
- I'm using Amazon Linux 2 on EC2, but the steps are probably similar for any CentOS / RHEL based Linux distribution. If using something Debian / Ubuntu based, your package management commands will differ (e.g. apt instead of yum) but you can probably muddle through it.
- A Maxmind account with which to download the "GeoIP Countries CSV" database. For non-commercial use, the free account tier works fine for this. Of course, you have options if you want to expand from there.
Steps:
2. Set up CPAN. I just took all the default options:
3. Install the required CPAN modules for the xt_geoip_build script:
4. Download and extract the latest xtables-addons build (3.18 at the time of this writing. Update the following commands for the version you download.)
# tar -xvf xtables-addons-3.18.tar.xz
# cd xtables-addons-3.18
5. Edit the "mconfig" file and comment out the modules you don't need. I commented out everything except "build_geoip=m" to build only the geoip module.
6. Build and install the selected xtables-addon modules.
7. If that went well, go into the "geoip" subdirectory under the xtables-addons build directory:
# cd geoip
8. Sign in to your Maxmind account, go to the "GeoIP Downloads" page, and find the link for the GeoLite2 Country: CSV Format database. (Note, you want the CSV format in particular.) I got this onto the server by copying the "Download ZIP Format" link and fetching it into the geoip directory with wget and extracting it:
# unzip geoip_country_csv.zip
9. Now you should have a GeoLite2-Country-CSV_YYYYMMDD folder (name will vary based on the age of the database. Substitute yours for YYYYMMDD.) You need to run the "xt_geoip_build_maxmind" perl script from inside that folder, with the destination set for where the iptables module will look for the output:
# ../xt_geoip_build_maxmind -D /usr/share/xt_geoip
10. If this went well, the script should build a series of files in /usr/share/xt_geoip and then show you a table of how many addresses are allocated to each country/region. Congrats!
Using this in IPTABLES:
The iptables command to drop traffic from, say, non-US addresses is:
I maintain a "blocklist" chain specifically for things I want to drop, but put it AFTER the "RELATED,ESTABLISHED" state rules. That way I can still initiate connections to foreign services, but clients outside the US can't initiate connections to my services. An example configuration to do that looks like this:
# iptables -A INPUT -m state --state INVALID -j DROP
# iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -A INPUT -i lo -j ACCEPT
# iptables -A INPUT -j blocklist
# iptables -A blocklist -m geoip ! --source-country US -j DROP
You can manage these with your own script, or do "iptables-save >/etc/sysconfig/iptables" to write the configuration to the sysconfig service that sets up iptables on boot.
If this works, you should be able to do an "iptables -L -n -v" and see a count of packets that have been dropped from other countries.
Chain blocklist (1 references)
pkts bytes target prot opt in out source destination
704 40777 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 -m geoip ! --source-country US
LPT: If you mess up iptables in such a way that you can't ssh into your host anymore, you can always log into the "serial console" via the AWS -> EC2 console -> Instance -> Actions -> Monitor & Troubleshoot -> Serial Console (It might make you enable it first, but that's a one step process.)
Addendum:
Good luck and have fun!