Пользовательские правила iptables для docker на примере zabbix

Задача: Закрыть все входящие соединение, кроме определенных ip адресов.

Имеется тестовая среда, состоящий из linux и трех windows c статическими ip адресами. На linux установлен docker образами zabbix, redmine. А на двух windows машинах установлены и настроены агенты от zabbix, на третьем нужно организовать возможность просмотра zabbix. Нужно ограничить других пользователей от zabbix сервера, но не ограничивая от redmine.

Все команды выполняются от имени root.

В официальной документации говорится о правиле iptables DOCKER-USER. Следует только это правило менять. Сперва смотрим какие правила есть, акцентируем внимание только на некоторых правилах.

Видно, что в правиле FORWARD первым стоит правило с target DOCKER-USER. Поэтому следует только его изменить.

iptables -L FORWARD -n -v
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
 421K  169M DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 419K  167M DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0

Из таблицы правил DOCKER можно увидеть какие порты и открыты и внутренние ip адреса контейнеров.

iptables -L DOCKER -n -v
Chain DOCKER (4 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     tcp  --  !docker_redmine docker_redmine  0.0.0.0/0            172.16.237.2         tcp dpt:3000
    0     0 ACCEPT     udp  --  !br-c56432fe07cc br-c56432fe07cc  0.0.0.0/0            172.16.238.2         udp dpt:162
    0     0 ACCEPT     tcp  --  !br-c56432fe07cc br-c56432fe07cc  0.0.0.0/0            172.16.238.3         tcp dpt:10051
    0     0 ACCEPT     tcp  --  !br-c56432fe07cc br-c56432fe07cc  0.0.0.0/0            172.16.238.4         tcp dpt:443
    5   248 ACCEPT     tcp  --  !br-c56432fe07cc br-c56432fe07cc  0.0.0.0/0            172.16.238.4         tcp dpt:80

В правиле DOCKER-USER нет особенных правил, все соединение пропускает через себя.

iptables -L DOCKER-USER -n -v
Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination
 4180 1634K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Первую очередь разберемся с сетью zabbix, а именно установим постоянную имя сети. Чтоб при пересоздании docker-compose имя сети не сменился. Из нынешнего состояния сети zabbix имеет сеть под именем br-c56432fe07cc, что не очень хорошо. В файле *.yaml добавим одну строку отвечающее за имя сети zbx_net_frontend: «com.docker.network.bridge.name: «docker_zabbix»».

Часть конфигурации:

networks:
  zbx_net_frontend:
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "false"
      com.docker.network.bridge.name: "docker_zabbix"

После пересоздаем сеть. Следует заменить на вашу *.yaml.

docker-compose -f docker-compose_v3_ubuntu_mysql_latest.yaml down
docker-compose -f docker-compose_v3_ubuntu_mysql_latest.yaml up -d

Cмотрим правило DOCKER.

iptables -L DOCKER -n -v
Chain DOCKER (4 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     tcp  --  !docker_redmine docker_redmine  0.0.0.0/0            172.16.237.2         tcp dpt:3000
    0     0 ACCEPT     udp  --  !docker_zabbix docker_zabbix  0.0.0.0/0            172.16.238.2         udp dpt:162
    0     0 ACCEPT     tcp  --  !docker_zabbix docker_zabbix  0.0.0.0/0            172.16.238.3         tcp dpt:10051
    0     0 ACCEPT     tcp  --  !docker_zabbix docker_zabbix  0.0.0.0/0            172.16.238.4         tcp dpt:443
    5   252 ACCEPT     tcp  --  !docker_zabbix docker_zabbix  0.0.0.0/0            172.16.238.4         tcp dpt:80

Осталось добавить правило в таблицу DOCKER-USER. Первом делом ведем правило DROP для всех подключений в сеть docker_zabbix из внешнего интерфейса (у меня eth0).

iptables -I DOCKER-USER -i eth0 -o docker_zabbix -j DROP

Сейчас все соединение запрещены в сеть docker_zabbix. Разрешим соединение для одного ip адреса, точнее сказать пакет может продолжить путь дальше по FORWARD.

iptables -I DOCKER-USER -i eth0 -s 192.168.43.55 -j RETURN

Здесь явным образом не указали сеть docker_zabbix. Проверяем доступность zabbix от хоста 192.168.43.55 с помощью powershell.

tnc 192.168.43.136 -port 8081
ComputerName     : 192.168.43.136
RemoteAddress    : 192.168.43.136
RemotePort       : 8081
InterfaceAlias   : vEthernet (Swich_in)
SourceAddress    : 192.168.43.55
TcpTestSucceeded : True

8081 порт открыт для zabbix docker. Чтоб удостовериться в том, что zabbix принадлежит 8081 порт.

docker ps
CONTAINER ID        IMAGE                                             COMMAND                  CREATED             STATUS                       PORTS                                           NAMES
c047f18a4445        zabbix/zabbix-web-nginx-mysql:ubuntu-4.2-latest   "docker-entrypoint.sh"   About an hour ago   Up About an hour (healthy)   0.0.0.0:8081->80/tcp, 127.0.0.1:8443->443/tcp   zabbix_zabbix-web-nginx-mysql_1

Но следует учесть, что в правилах надо указывать порт 80, а не 8081. Если указать порт 8081, то не откроется доступ к zabbix. Для второго хоста команда.

iptables -I DOCKER-USER -i eth0 -p tcp --dport 80 -s 192.168.43.10 -j RETURN

Для третьего хоста откроем только порт 10051, на этом хосте используется активный агент.

iptables -I DOCKER-USER -i eth0 -p tcp --dport 10051 -s 192.168.43.13 -j RETURN

Еще одна проблема, не можем из контейнеров выйти в внешний мир. Не работают скрипты оповещение и не может проверить доступность сайтов. Осталось еще одна команда для разрешение уже имеющих соединений.

iptables -I DOCKER-USER -i eth0 -o docker_zabbix -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Не забываем, что после перезагрузки сервера созданные правило стираются.

Комментарии 3

    0
    Каждый раз, когда меняется ip контейнера, меняем iptables правила?
      0
      Нет, правила работает для всего подсети docker_zabbix. IP адрес контейнера внутри этой подсети.
        0
        Не забываем, что после перезагрузки сервера созданные правило стираются.


        check_tables.sh
        #!/usr/bin/bash
        ips=("1.2.3.4" "5.6.7.8" "9.10.11.12")
        
        # проверить правило-дырку
        /usr/sbin/iptables -C DOCKER-USER -j RETURN 2>> /dev/null
        if [[ $? -eq 0 ]]
        then /usr/sbin/iptables -D DOCKER-USER -j RETURN
        fi
        
        # проверить запрет на доступ
        /usr/sbin/iptables -C DOCKER-USER -i eth0 -j DROP 2>> /dev/null
        if [[ $? -eq 1 ]]
        then /usr/sbin/iptables -A DOCKER-USER -i eth0 -j DROP
        fi
        
        # проверить разрешение на доступ по ip
        for ip in ${ips[@]}; do
         /usr/sbin/iptables -C DOCKER-USER -s $ip/32 -i eth0 -j RETURN 2>> /dev/null
         if [[ $? -eq 1 ]]
         then /usr/sbin/iptables -I DOCKER-USER 1 -s $ip -i eth0 -j RETURN
         fi
        done
        exit 0
        

        и добавляем это в cron (crontab -e например)

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое