Compare commits

...

5 Commits

Author SHA1 Message Date
8dd7663b3c roles/common: Use Abuse.ch's SSL Blacklist in nftables
This adds Abuse.sh's list of IPs using blacklisted SSL certificates
to nftables. These IPs are high confidence indicators of compromise
and we should not route them. The list is updated daily by a systemd
timer.

See: https://sslbl.abuse.ch/blacklist/
2021-07-29 10:16:00 +03:00
cba2a7a996 roles/common: Fix nftables in Debian firewall
The previous commit meant to move the service start, not the config
copying task.
2021-07-29 10:10:04 +03:00
197bdf7666 roles/common: Start nftables service later
We should only try to start the nftables service after we finish
copying all the config files just in case there is some unclean
state in one of them. On a first run this shouldn't matter, but
after nftables and some abuse list update scripts have run this
can happen (mostly in testing!).
2021-07-29 10:05:15 +03:00
46fc2ce3d4 roles/common: Move cleanup to a one-off play
We only need to run this once on existing hosts that are using the
old firewalld/ipsets setup before applying the new nftables config.
2021-07-29 10:00:30 +03:00
b4d50166f4 roles/common: Fix loop in firewall cleanup 2021-07-28 23:46:53 +03:00
8 changed files with 154 additions and 62 deletions

View File

@@ -0,0 +1,5 @@
#!/usr/sbin/nft -f
define ABUSECH_IPV4 = {
192.168.254.254
}

View File

@@ -0,0 +1,27 @@
[Unit]
Description=Update Abuse.ch SSL Blacklist IPs
# This service will fail if nftables is not running so we use Requires to make
# sure that nftables is started.
Requires=nftables.service
# Make sure the network is up and nftables is started
After=network-online.target nftables.service
Wants=network-online.target update-abusech-nftables.timer
[Service]
# https://www.ctrl.blog/entry/systemd-service-hardening.html
# Doesn't need access to /home or /root
ProtectHome=true
# Possibly only works on Ubuntu 18.04+
ProtectKernelTunables=true
ProtectSystem=full
# Newer systemd can use ReadWritePaths to list files, but this works everywhere
ReadWriteDirectories=/etc/nftables
PrivateTmp=true
WorkingDirectory=/var/tmp
SyslogIdentifier=update-abusech-nftables
ExecStart=/usr/bin/flock -x update-abusech-nftables.lck \
/usr/local/bin/update-abusech-nftables.sh
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
#
# update-abuseipdb-nftables.sh v0.0.1
#
# Download IP addresses seen using a blacklisted SSL certificate and load them
# into nftables sets. As of 2021-07-28 these appear to only be IPv4.
#
# See: https://sslbl.abuse.ch/blacklist
#
# Copyright (C) 2021 Alan Orth
#
# SPDX-License-Identifier: GPL-3.0-only
# Exit on first error
set -o errexit
abusech_ipv4_set_path=/etc/nftables/abusech-ipv4.nft
abusech_list_temp=$(mktemp)
echo "Downloading Abuse.sh SSL Blacklist IPs"
abusech_response=$(curl -s -G -w "%{http_code}\n" https://sslbl.abuse.ch/blacklist/sslipblacklist.txt --output "$abusech_list_temp")
if [[ $abusech_response -ne 200 ]]; then
echo "Abuse.ch responded: HTTP $abusech_response"
exit 1
fi
if [[ -f "$abusech_list_temp" ]]; then
echo "Processing IPv4 list"
abusech_ipv4_list_temp=$(mktemp)
abusech_ipv4_set_temp=$(mktemp)
# Remove comments, DOS carriage returns, and IPv6 addresses (even though
# Abuse.ch seems to only have IPv4 addresses, let's not break our shit on
# that assumption some time down the line).
sed -e '/#/d' -e 's/
//' -e '/:/d' "$abusech_list_temp" > "$abusech_ipv4_list_temp"
echo "Building abusech-ipv4 set"
cat << NFT_HEAD > "$abusech_ipv4_set_temp"
#!/usr/sbin/nft -f
define ABUSECH_IPV4 = {
NFT_HEAD
while read -r network; do
# nftables doesn't mind if the last element in the set has a trailing
# comma so we don't need to do anything special here.
echo "$network," >> "$abusech_ipv4_set_temp"
done < $abusech_ipv4_list_temp
echo "}" >> "$abusech_ipv4_set_temp"
install -m 0600 "$abusech_ipv4_set_temp" "$abusech_ipv4_set_path"
rm -f "$abusech_list_temp" "$abusech_ipv4_list_temp" "$abusech_ipv4_set_temp"
fi
echo "Reloading nftables"
# The abusech nftables sets are included by nftables.conf

View File

@@ -0,0 +1,12 @@
[Unit]
Description=Update Abuse.ch SSL Blacklist IPs
[Timer]
# Once a day at midnight
OnCalendar=*-*-* 00:00:00
# Add a random delay of 03600 seconds
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target

View File

@@ -23,10 +23,6 @@
- name: Install firewall packages
apt: pkg={{ debian_firewall_packages }} state=present cache_valid_time=3600
- name: Start and enable nftables
when: ansible_distribution_major_version is version('11', '>=')
systemd: name=nftables state=started enabled=yes
- name: Copy nftables.conf
when: ansible_distribution_major_version is version('11', '>=')
template: src=nftables.conf.j2 dest=/etc/nftables.conf owner=root mode=0644
@@ -43,6 +39,7 @@
loop:
- spamhaus-ipv4.nft
- spamhaus-ipv6.nft
- abusech-ipv4.nft
notify:
- reload nftables
@@ -106,20 +103,23 @@
loop:
- update-spamhaus-nftables.sh
- aggregate-cidr-addresses.pl
- update-abusech-nftables.sh
- name: Copy Spamhaus nftables systemd units
- name: Copy nftables systemd units
when: ansible_distribution_version is version('11', '>=')
copy: src={{ item }} dest=/etc/systemd/system/{{ item }} mode=0644 owner=root group=root
loop:
- update-spamhaus-nftables.service
- update-spamhaus-nftables.timer
register: spamhaus_nftables_systemd_units
- update-abusech-nftables.service
- update-abusech-nftables.timer
register: nftables_systemd_units
# need to reload to pick up service/timer/environment changes
- name: Reload systemd daemon
systemd: daemon_reload=yes
when: spamhaus_firewalld_systemd_units is changed or
spamhaus_nftables_systemd_units is changed
nftables_systemd_units is changed
- name: Start and enable Spamhaus firewalld update timer
when: ansible_distribution_version is version('10', '<=')
@@ -127,9 +127,16 @@
notify:
- restart firewalld
- name: Start and enable Spamhaus nftables update timer
- name: Start and enable nftables update timers
when: ansible_distribution_version is version('11', '>=')
systemd: name=update-spamhaus-nftables.timer state=started enabled=yes
systemd: name={{ item }} state=started enabled=yes
loop:
- update-spamhaus-nftables.timer
- update-abusech-nftables.timer
- name: Start and enable nftables
when: ansible_distribution_major_version is version('11', '>=')
systemd: name=nftables state=started enabled=yes
- include_tasks: fail2ban.yml
when: ansible_distribution_major_version is version('9', '>=')

View File

@@ -4,9 +4,6 @@
# Ubuntu 16.04 will use firewalld with the iptables backend.
- block:
- include_tasks: firewall_Ubuntu_cleanup.yml
when: ansible_distribution_version is version('20.04', '==')
- name: Set Ubuntu firewall packages
when: ansible_distribution_version is version('20.04', '<')
set_fact:
@@ -32,10 +29,6 @@
when: ansible_distribution_version is version('16.04', '>=')
apt: pkg=ufw state=absent
- name: Start and enable nftables
when: ansible_distribution_version is version('20.04', '>=')
systemd: name=nftables state=started enabled=yes
- name: Copy nftables.conf
when: ansible_distribution_version is version('20.04', '>=')
template: src=nftables.conf.j2 dest=/etc/nftables.conf owner=root mode=0644
@@ -52,6 +45,7 @@
loop:
- spamhaus-ipv4.nft
- spamhaus-ipv6.nft
- abusech-ipv4.nft
notify:
- reload nftables
@@ -88,26 +82,29 @@
- update-spamhaus-lists.timer
register: spamhaus_firewalld_systemd_units
- name: Copy Spamhaus nftables update scripts
- name: Copy nftables update scripts
when: ansible_distribution_version is version('20.04', '>=')
copy: src={{ item }} dest=/usr/local/bin/{{ item }} mode=0755 owner=root group=root
loop:
- update-spamhaus-nftables.sh
- aggregate-cidr-addresses.pl
- update-abusech-nftables.sh
- name: Copy Spamhaus nftables systemd units
- name: Copy nftables systemd units
when: ansible_distribution_version is version('20.04', '>=')
copy: src={{ item }} dest=/etc/systemd/system/{{ item }} mode=0644 owner=root group=root
loop:
- update-spamhaus-nftables.service
- update-spamhaus-nftables.timer
register: spamhaus_nftables_systemd_units
- update-abusech-nftables.service
- update-abusech-nftables.timer
register: nftables_systemd_units
# need to reload to pick up service/timer/environment changes
- name: Reload systemd daemon
systemd: daemon_reload=yes
when: spamhaus_firewalld_systemd_units is changed or
spamhaus_nftables_systemd_units is changed
nftables_systemd_units is changed
- name: Start and enable Spamhaus firewalld update timer
when: ansible_distribution_version is version('18.04', '<=')
@@ -115,9 +112,16 @@
notify:
- restart firewalld
- name: Start and enable Spamhaus nftables update timer
- name: Start and enable nftables update timers
when: ansible_distribution_version is version('20.04', '>=')
systemd: name=update-spamhaus-nftables.timer state=started enabled=yes
systemd: name={{ item }} state=started enabled=yes
loop:
- update-spamhaus-nftables.timer
- update-abusech-nftables.timer
- name: Start and enable nftables
when: ansible_distribution_version is version('20.04', '>=')
systemd: name=nftables state=started enabled=yes
- include_tasks: fail2ban.yml
when: ansible_distribution_version is version('16.04', '>=')

View File

@@ -1,40 +0,0 @@
---
# Clean up previous firewalld configuration on Ubuntu 20.04, now that we are
# migrating to a pure nftables configuration.
- name: Stop and disable firewalld
systemd: name=nftables state=stopped enabled=no
- name: Set Ubuntu firewall packages to remove
set_fact:
ubuntu_firewall_packages:
- firewalld
- tidy
- name: Remove old firewall packages
apt: pkg={{ ubuntu_firewall_packages }} state=absent
- name: Remove old firewalld zone and ipsets
file: dest={{ item }} state=absent
loop:
- /etc/firewalld/zones/public.xml
- /etc/firewalld/ipsets/abusers-ipv4.xml
- /etc/firewalld/ipsets/abusers-ipv6.xml
- /etc/firewalld/ipsets/spamhaus-ipv4.xml
- /etc/firewalld/ipsets/spamhaus-ipv6.xml
- name: Stop and disable old Spamhaus firewalld systemd timer
systemd: name=update-spamhaus-lists.timer state=stopped enabled=no
- name: Remove old Spamhaus firewalld update script and systemd units
file: dest=/usr/local/bin/update-spamhaus-lists.sh state=absent
loop:
- /usr/local/bin/update-spamhaus-lists.sh
- /etc/systemd/system/update-spamhaus-lists.service
- /etc/systemd/system/update-spamhaus-lists.timer
# need to reload to pick up service/timer/environment changes
- name: Reload systemd daemon
systemd: daemon_reload=yes
# vim: set sw=2 ts=2:

View File

@@ -9,6 +9,9 @@ flush ruleset
include "/etc/nftables/spamhaus-ipv4.nft"
include "/etc/nftables/spamhaus-ipv6.nft"
# Lists updated daily by update-abusech-nftables.sh
include "/etc/nftables/abusech-ipv4.nft"
# Notes:
# - tables hold chains, chains hold rules
# - inet is for both ipv4 and ipv6
@@ -26,6 +29,11 @@ table inet filter {
elements = $SPAMHAUS_IPV6
}
set abusech-ipv4 {
type ipv4_addr
elements = $ABUSECH_IPV4
}
chain input {
type filter hook input priority 0;
@@ -39,6 +47,9 @@ table inet filter {
ip saddr @spamhaus-ipv4 counter drop
ip6 saddr @spamhaus-ipv6 counter drop
# Drop packets matching the abusech set early.
ip saddr @abusech-ipv4 counter drop
# Allow loopback traffic.
iifname lo accept
@@ -83,5 +94,8 @@ table inet filter {
# Drop outgoing packets matching the spamhaus sets too
ip daddr @spamhaus-ipv4 counter drop
ip6 daddr @spamhaus-ipv6 counter drop
# Drop outgoing packets matching the abusech sets too
ip daddr @abusech-ipv4 counter drop
}
}