Скрипт управления списком IP-сетей в iptables/ipset для PostgreSQL
Содержание
Введение
На работе до сих пор на некоторых серверах удавалось обходиться без настройки фильтрации трафика. Сервисов установлено немного, у каждого есть собственные средства ограничения подключений. В частности, одними из таких серверов были серверы с PostgreSQL, на которых установлены только сервер SSH, Zabbix-агент, PostgreSQL и PgBouncer. Доступ к SSH можно ограничить с помощью файла /etc/hosts.allow, у Zabbix-агента можно указать списки IP-адресов в опции Server в файле конфигурации /etc/zabbix/zabbix_agentd.conf, ограничить доступ к PostgreSQL и PgBouncer можно при помощи файла /etc/postgresql/15/main/pg_hba.conf. Однако по мнению отдела информационной безопасности этого недостаточно и нужно не просто ограничить доступ к сервисам, но и вообще скрыть сам факт существования этих сервисов от посторонних. И это несмотря на то, что серверы имеют серые IP-адреса.
Задача прописывать доступ в файл /etc/postgresql/15/main/pg_hba.conf для пользователей БД при этом никуда не девается, но возникает необходимость синхронно менять ещё и списки IP-адресов в ipset, что чревато ошибками. Чтобы избежать ошибок, я решил вновь прибегнуть к подходу, описанному в статье Скрипты управления списком IP-адресов в iptables/ipset и ipfw/table, переработав скрипт для текущей задачи.
Установка пакетов
Первым делом установим необходимые пакеты:
# apt-get install netfilter-persistent iptables-persistent ipset-persistent iptables ipset gawk aggregate
Настройка скрипта
Создадим скрипт /usr/local/bin/ipset_auto.sh со следующим содержимым:
#!/bin/sh
GAWK="/usr/bin/gawk"
SORT="/usr/bin/sort"
UNIQ="/usr/bin/uniq"
IPSET="/sbin/ipset"
XARGS="/usr/bin/xargs"
AGG="/usr/bin/aggregate"
update()
{
SET="$1"
NEED_IPS="$2"
CURRENT_IPS=`$IPSET list $SET | $GAWK '/^([0-9]{1,3}\.){3}[0-9]{1,3}(|\/[0-9]{1,2})$/ { if ($0 ~ "/") { print $0; } else { print $0 "/32"; } }'`
DIFF_IPS=`(echo "$NEED_IPS" ; echo -n "$CURRENT_IPS") | $SORT | $UNIQ -u`
ADD_IPS=`(echo "$NEED_IPS" ; echo -n "$DIFF_IPS") | $SORT | $UNIQ -d`
DEL_IPS=`(echo "$CURRENT_IPS" ; echo -n "$DIFF_IPS") | $SORT | $UNIQ -d`
if [ -n "$ADD_IPS" ]
then
echo "--- $SET add ---"
echo "$ADD_IPS"
echo "$ADD_IPS" | $XARGS -n1 $IPSET add $SET
fi
if [ -n "$DEL_IPS" ]
then
echo "--- $SET del ---"
echo "$DEL_IPS"
echo "$DEL_IPS" | $XARGS -n1 $IPSET del $SET
fi
}
NEED_NETS=`$GAWK '/^host\s*/ && $4 != "::1/128" && $4 != "127.0.0.1/32" { print $4; }' /etc/postgresql/15/main/pg_hba.conf | $AGG -q`
if [ -z "$NEED_NETS" ]
then
echo "Failed to prepare needed networks"
exit
fi
update "postgres_auto" "$NEED_NETS"
Добавим скрипту права на выполнение:
# chmod +x /usr/local/bin/ipset_auto.sh
Как видно из скрипта, он обновляет в ipset список сетей под названием postgres_auto.
Для создания списка сетей postgres_auto в ipset можно воспользоваться командой:
# ipset create postgres_auto hash:net
Выполним скрипт вручную, чтобы наполнить список сетями:
# /usr/local/bin/ipset_auto.sh
Проверить содержимое списка можно с помощью такой команды:
# ipset list postgres_auto
Чтобы список обновлялся автоматически раз в минуту, запустим команду редактирования задач планировщика:
# crontab -e
И добавим в него строчку:
* * * * * /usr/local/bin/ipset_auto.sh
Настройка iptables
Для создания правила в iptables, которое разрешит всем сетям из множества postgre_auto взаимодействовать с сервером PostgreSQL и его прокси PgBouncer, можно воспользоваться командой:
# iptables -A INPUT -p tcp -m set --match-set postgres_auto src -m multiport --dports 5432,6432 -j ACCEPT
В моём случае iptables ещё не был настроен и я поместил в файл /etc/iptables/rules.v4 примерно такие правила (реальный список правил не привожу для упрощения и по соображениям безопасности):
*filter
:INPUT DROP [99531963:5114253625]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [41237204127:25059350107297]
-A INPUT -s 127.0.0.1/32 -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m icmp ! --icmp-type 5 -j ACCEPT
-A INPUT -s 88.88.88.88/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -s 99.99.99.99/32 -p tcp -m tcp --dport 10050 -j ACCEPT
-A INPUT -p tcp -m set --match-set postgres_auto src -m multiport --dports 5432,6432 -j ACCEPT
COMMIT
В приведённом выше примере IP-адрес 88.88.88.88 - это адрес, откуда к серверу разрешено подключаться по SSH, а IP-адрес 99.99.99.99 - адрес сервера Zabbix.
Для применения правил можно воспользоваться командой:
# netfilter-persistent reload