Скрипт управления списком IP-сетей в iptables/ipset для MySQL
Содержание
Введение
На работе до сих пор на некоторых серверах удавалось обходиться без настройки фильтрации трафика. Сервисов установлено немного, у каждого есть собственные средства ограничения подключений. В частности, одними из таких серверов были серверы с MySQL, на которых установлены только сервер SSH, Zabbix-агент и сам MySQL. Доступ к SSH можно ограничить с помощью файла /etc/hosts.allow, у Zabbix-агента можно указать списки IP-адресов в опции Server в файле конфигурации /etc/zabbix/zabbix_agentd.conf, доступ к MySQL ограничивается сочетанием пользователя и IP-адреса. Однако по мнению отдела информационной безопасности этого недостаточно и нужно не просто ограничить доступ к сервисам, но и вообще скрыть сам факт существования этих сервисов от посторонних. И это несмотря на то, что серверы имеют серые IP-адреса.
Задача ограничивать доступ БД сочетанием пользователя и IP-адреса при этом никуда не девается, но возникает необходимость синхронно менять ещё и списки IP-адресов в ipset, что чревато ошибками. Чтобы избежать ошибок, я решил вновь прибегнуть к подходу, описанному в статье Скрипты управления списком IP-адресов в iptables/ipset и ipfw/table, переработав скрипт для текущей задачи.
Установка пакетов
Первым делом установим необходимые пакеты:
# apt-get install netfilter-persistent iptables-persistent ipset-persistent iptables ipset gawk
Настройка скрипта
Создадим скрипт /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"
MYSQL="/usr/bin/mysql"
update()
{
SET="$1"
NEED_IPS="$2"
CURRENT_IPS=`$IPSET list $SET | $GAWK '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ { print $0; }'`
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_IPS=`$MYSQL -N mysql <<END 2>/dev/null
SELECT host
FROM user
WHERE host LIKE '%.%.%.%'
GROUP BY host;
END
`
ERROR=$?
if [ $ERROR -ne 0 ]
then
echo "Failed to execute SQL-query"
exit
fi
update "mysql_auto" "$NEED_IPS"
Добавим скрипту права на выполнение:
# chmod +x /usr/local/bin/ipset_auto.sh
Как видно из скрипта, он обновляет в ipset список сетей под названием mysql_auto.
Для создания списка сетей postgres_auto в ipset можно воспользоваться командой:
# ipset create mysql_auto hash:ip
Выполним скрипт вручную, чтобы наполнить список сетями:
# /usr/local/bin/ipset_auto.sh
Проверить содержимое списка можно с помощью такой команды:
# ipset list mysql_auto
Чтобы список обновлялся автоматически раз в минуту, запустим команду редактирования задач планировщика:
# crontab -e
И добавим в него строчку:
* * * * * /usr/local/bin/ipset_auto.sh
Настройка iptables
Для создания правила в iptables, которое разрешит всем сетям из множества postgre_auto взаимодействовать с сервером MySQL, можно воспользоваться командой:
# iptables -A INPUT -p tcp -m set --match-set mysql_auto src -m multiport --dports 3306 -j ACCEPT
В моём случае iptables ещё не был настроен и я поместил в файл /etc/iptables/rules.v4 такие правила:
*filter
:INPUT DROP [372:15672]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [21185:2417175]
-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 -p tcp -m set --match-set ssh src -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 nodes src -m multiport --dports 3306,4444,4567,4568 -j ACCEPT
-A INPUT -p tcp -m set --match-set mysql_auto src -m tcp --dport 3306 -j ACCEPT
-A INPUT -d 224.0.0.18/32 -p ah -m set --match-set nodes src -j ACCEPT
-A INPUT -d 224.0.0.18/32 -p vrrp -m set --match-set nodes src -j ACCEPT
COMMIT
В приведённом выше примере IP-адрес 99.99.99.99 - адрес сервера Zabbix. IP-адреса, имеющие доступ по SSH, нужно поместить в список ssh в ipset. Сервер в приведённом примере является частью кластера Galera, IP-адреса узлов, входящих в кластер, нужно поместить в список nodes в ipset.
Сохраним списки адресов в ipset в файл /etc/iptables/ipsets с помощью команды:
# ipset save > /etc/iptables/ipsets
Теперь для применения правил из файла /etc/iptables/rules.v4 можно воспользоваться командой:
# netfilter-persistent reload