Skip to content

Instantly share code, notes, and snippets.

@adamancini
Forked from eusonlito/README.md
Created October 25, 2021 22:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamancini/46d5c134dee4e5517068f4f8c9b6c38c to your computer and use it in GitHub Desktop.
Save adamancini/46d5c134dee4e5517068f4f8c9b6c38c to your computer and use it in GitHub Desktop.
Strong iptables and ipset protection

Protect your server with a strong iptables rules and ipset lists.

1. Install ipset to manage ipstables lists

apt install ipset

2. Install iptables-persistent to preserve iptables rules on reboot

apt install iptables-persistent

3. Create ipset lists

# iptables fails on real SSH port will be blocked 24 hours
ipset create ssh-real hash:ip timeout 86400

# iptables INPUT connections on default SSH port will be blocked forever
ipset create ssh hash:ip

# iptables INPUT connections on FTP port will be blocked forever
ipset create ftp hash:ip

# iptables INPUT connections on MySQL, PostgreSQL and MongoDB ports will be blocked forever
ipset create mysql hash:ip
ipset create postgresql hash:ip
ipset create mongodb hash:ip

# iptables INPUT connections on any mail related port will be blocked forever
ipset create mail hash:ip

# iptables INPUT connections on Plesk and WHM/cPanel ports will be blocked forever
ipset create plesk hash:ip
ipset create cpanel hash:ip

# register rules
ipset save -file /etc/iptables/ipset

4. Paste the rules.v4 contents into file /etc/iptables/rules.v4

  • Replace the XXX.XXX.XXX.XXX ip with a safe to connect IP, it will be your lifeguard.
  • Replace the port 987 with your real SSH port (always different than 22).

5. Test the iptables rules with iptables-apply

iptables-apply -t 60 /etc/iptables/rules.v4

6. Apply rules

iptables-restore < /etc/iptables/rules.v4

7. Check ipset status

ipset list

8. Persistent ipset

Create file /etc/systemd/system/ipset-persistent.service with:

[Unit]
Description=ipset persistent configuration
Before=network.target

# ipset sets should be loaded before iptables
# Because creating iptables rules with names of non-existent sets is not possible
Before=netfilter-persistent.service
Before=ufw.service

ConditionFileNotEmpty=/etc/iptables/ipset

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/ipset restore -file /etc/iptables/ipset
ExecStop=/usr/sbin/ipset save -file /etc/iptables/ipset
ExecStop=/usr/sbin/ipset flush
ExecStopPost=/usr/sbin/ipset destroy

[Install]
WantedBy=multi-user.target

RequiredBy=netfilter-persistent.service
RequiredBy=ufw.service

Enable service with

systemctl daemon-reload
systemctl enable ipset-persistent.service

Thanks to https://selivan.github.io/2018/07/27/ipset-save-with-ufw-and-iptables-persistent-and.html

9. Install a script to geolocate blocked IPs

https://gist.github.com/eusonlito/5afa0d42f1aff3cd2b82a8c0a8a3b75d

10. Flush iptables rules

The default INPUT rule is DROP, then you can not flush rules with iptables -F or your access will be blocked forever.

You need to execute:

iptables -P INPUT   ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT  ACCEPT
iptables -F
iptables -X
[Unit]
Description=ipset persistent configuration
Before=network.target
# ipset sets should be loaded before iptables
# Because creating iptables rules with names of non-existent sets is not possible
Before=netfilter-persistent.service
Before=ufw.service
ConditionFileNotEmpty=/etc/iptables/ipset
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/ipset restore -file /etc/iptables/ipset
ExecStop=/usr/sbin/ipset save -file /etc/iptables/ipset
ExecStop=/usr/sbin/ipset flush
ExecStopPost=/usr/sbin/ipset destroy
[Install]
WantedBy=multi-user.target
RequiredBy=netfilter-persistent.service
RequiredBy=ufw.service
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# Always allow this IP
-A INPUT -s XXX.XXX.XXX.XXX/32 -j ACCEPT
# Accept any related or established connections
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# Allow all traffic on the loopback interface
-A INPUT -i lo -j ACCEPT
# Allow input PING
-A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# Drops invalid incoming packets
-A INPUT -m conntrack --ctstate INVALID -j DROP
# Block real SSH port after 5 attempts in 5 minutes
-A INPUT -m set --match-set ssh-real src -j DROP
-A INPUT -p tcp --dport 987 -m state --state NEW -m recent --set --name ssh-real --rsource
-A INPUT -m recent --update --seconds 300 --hitcount 5 --rttl --name ssh --rsource -j SET --add-set ssh-real src
-A INPUT -m set --match-set ssh-real src -j LOG --log-prefix "[FIREWALL] [SSH-REAL] " --log-level 4
-A INPUT -m set --match-set ssh-real src -j DROP
# Block all attempts on default SSH port 22
-A INPUT -m set --match-set ssh src -j DROP
-A INPUT -p tcp -m tcp --dport 22 -j SET --add-set ssh src
-A INPUT -m set --match-set ssh src -j LOG --log-prefix "[FIREWALL] [SSH] " --log-level 4
-A INPUT -m set --match-set ssh src -j DROP
# Block all attempts on default FTP port 21
-A INPUT -m set --match-set ftp src -j DROP
-A INPUT -p tcp -m tcp --dport 21 -j SET --add-set ftp src
-A INPUT -m set --match-set ftp src -j LOG --log-prefix "[FIREWALL] [FTP] " --log-level 4
-A INPUT -m set --match-set ftp src -j DROP
# Block all attempts on default MySQL port 3306
-A INPUT -m set --match-set mysql src -j DROP
-A INPUT -p tcp -m tcp --dport 3306 -j SET --add-set mysql src
-A INPUT -m set --match-set mysql src -j LOG --log-prefix "[FIREWALL] [MYSQL] " --log-level 4
-A INPUT -m set --match-set mysql src -j DROP
# Block all attempts on default PostgreSQL port 5432
-A INPUT -m set --match-set postgresql src -j DROP
-A INPUT -p tcp -m tcp --dport 5432 -j SET --add-set postgresql src
-A INPUT -m set --match-set postgresql src -j LOG --log-prefix "[FIREWALL] [POSTGRESQL] " --log-level 4
-A INPUT -m set --match-set postgresql src -j DROP
# Block all attempts on default MongoDB port 27017
-A INPUT -m set --match-set mongodb src -j DROP
-A INPUT -p tcp -m tcp --dport 27017 -j SET --add-set mongodb src
-A INPUT -m set --match-set mongodb src -j LOG --log-prefix "[FIREWALL] [MONGODB] " --log-level 4
-A INPUT -m set --match-set mongodb src -j DROP
# Block all attempts on mail related ports
-A INPUT -m set --match-set mail src -j DROP
-A INPUT -p tcp -m tcp -m multiport --dports 25,2525,465,587,110,143,993 -j SET --add-set mail src
-A INPUT -m set --match-set mail src -j LOG --log-prefix "[FIREWALL] [MAIL] " --log-level 4
-A INPUT -m set --match-set mail src -j DROP
# Block all attempts on Plesk related ports 8443 and 8880
-A INPUT -m set --match-set plesk src -j DROP
-A INPUT -p tcp -m tcp -m multiport --dports 8443,8880 -j SET --add-set plesk src
-A INPUT -m set --match-set plesk src -j LOG --log-prefix "[FIREWALL] [PLESK] " --log-level 4
-A INPUT -m set --match-set plesk src -j DROP
# Block all attempts on WHM/cPanel related ports 2082,2083,2086,2087,2089
-A INPUT -m set --match-set cpanel src -j DROP
-A INPUT -p tcp -m tcp -m multiport --dports 2082,2083,2086,2087,2089 -j SET --add-set cpanel src
-A INPUT -m set --match-set cpanel src -j LOG --log-prefix "[FIREWALL] [CPANEL] " --log-level 4
-A INPUT -m set --match-set cpanel src -j DROP
# Accept input on open ports
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 987 -j ACCEPT
COMMIT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment