iptables Linux или нужно писать скрипты?

У меня есть сервера, которые находятся в приватной сети: 10.17.0.0/16. Я решил разбить эту сеть по 18-ой маске. 10.17.0.0/18 -- ПРОД сервера. В этой подсети машины общаются друг с другом без ограничений. Остальные диапазоны (10.17.64.0/18, 10.17.128.0.0/18...) не могут обращаться на эти сервера.
Практически все приложения у меня крутятся в docker. Я настроил правила фаервола (iptables) для INPUT и OUTPUT и в целом все работает. Однако у меня возникает следующая проблема:
Докер при старте добавляет собственные правила в цепочку FORWARD. Эти правила разрешают проход любого трафика внутрь приватной сети docker. Таким образом все машины из всех подсетей могут обращаться к моим приложениям (стоит добавить, что у каждой машины есть белый IP).
Я добавил в цепочку FORWARD правило (на 1 место):

iptables -I FORWARD 1 ! -s 10.17.0.0/18 -m conntrack --ctstate NEW -j DROP

И в целом это работает. Я сохраняю правила (service netfilter-persistent save) и перезапускаю машину. И после подключения вижу следующее:

DOCKER-USER  all  --  anywhere             anywhere            
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere
DROP       all  -- !10.17.0.0/18         anywhere             ctstate NEW

То есть мое правило сдвинулось вниз и теперь не работает нормально! Я сделал небольшую хитрость: Я добавил в /etc/bash.bashrc команду выше и теперь правило добавляется правильно. Но это ужасный костыль, совсем не расширяемо и не похоже на гуд-практик (теперь при каждом подключении к машине добавляется это правило и что если я захочу добавить пару специфичных правил?..)
Прошу, подскажите в какую сторону смотреть, что изучить, чтобы избежать написания скриптов в bash и чтобы мои правила были приоритетнее правил докера..

--- UPDATED ---
У меня есть контейнер Kafka (с Kraft). Я добавил следующие правила в DOCKER-USER:

iptables -I DOCKER-USER 1 -s 10.17.64.0/18 -j RETURN   
iptables -I DOCKER-USER 2 -s 172.0.0.0/8 -j RETURN    
iptables -I DOCKER-USER 3 -j DROP     

Эти правила я добавляю на сервер с контейнером Kafka.
Я использую 10.17.64.0/18 потому что экспериментирую в другом контуре.
Когда я добавляю эти правила соединение с моим kafka из приложения (на другом хосте в той же подсети(10.17.64.0/18)) не работает...
P.S.
Я использую чистые правила iptables с docker. Из всех моих изменений в этом контуре только те, что написал выше
P.S.S.
Примечательно то, что в остальном это работает. Я поднимаю контейнер nginx и доступ к нему есть только из приватной сети, попытка обращения через ext-ip обрывается с таймаут. Но именно kafka с этими правилами перестает работать:(


Ответы (2 шт):

Автор решения: Mr Cypher

Пока что решил проблему следующим образом:

  • Сделал файл скрипта, в котором очищаю правила INPUT и OUTPUT. FORWARD не трогаю (так как docker должен будет положить свои правила):

    #!/bin/bash
    iptables -P INPUT ACCEPT
    iptables -P OUTPUT ACCEPT
    
    # FLUSH OUTPUT and INPUT
    iptables -F INPUT
    iptables -F OUTPUT
    
    # INPUT
    iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
    iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
    iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
    iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
    iptables -A INPUT -s 10.17.0.0/18 -j ACCEPT
    
    # FORWARD
    iptables -I FORWARD 1 -s 172.0.0.0/8 -j ACCEPT
    iptables -I FORWARD 2 -s 172.0.0.0/8 -d 172.0.0.0/8 -j ACCEPT
    iptables -I FORWARD 3 ! -s 10.17.0.0/18 -j DROP
    
    iptables -P INPUT DROP
    
  • Далее добавил файл сервиса, который будет запускать этот скрипт после docker.service (WantedBy для активации скрипта)

    [Install]
    WantedBy=multi-user.target
    
    [Unit]
    Description=Settings Iptables Rules
    After=docker.service
    
    [Service]
    Type=oneshot
    ExecStart={{ iptables_script_file }}
    
  • Закинул это в ENV для скрипта и Ansible-плейбуком раскатываю:

    ---
    - name: Setting Firewall
      hosts: dmz
      become: true
      gather_facts: false
    
      pre_tasks:
        - name: Include Settings
          include_vars: "{{ playbook_dir }}/secrets/dmz-firewall.yml"
          tags:
            - always
    
      tasks:
        - name: Create directory for script
          file:
            path: "{{ iptables_script_dir }}"
            state: directory
    
        - name: Save Script From Variable
          shell: "echo '{{ iptables_script }}' > {{ iptables_script_file }}"
    
        - name: Set script as Executable
          file:
            path: "{{ iptables_script_file }}"
            mode: 0550
    
        - name: Create directory for service
          file:
            path: "{{ iptables_service_dir }}"
            state: directory
    
        - name: Save Service From Variable
          shell: "echo '{{ iptables_service }}' > {{ iptables_service_file }}"
    
        - name: Systemd Daemon Reload
          systemd_service:
            daemon_reload: true
    
        - name: Enable and Restart Service
          systemd_service:
            name: "{{ iptables_service_filename }}"
            enabled: true
            state: restarted
    

P.S. Добавляю это сюда, чтобы может быть помочь кому-то.

P.P.S. Не уверяю в 100%-ой правильности, у меня сделано так, и это работает.

Если у кого-то есть решение лучше, прошу, дайте другой ответ.

→ Ссылка
Автор решения: eri
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -o br-9373f0a8d417 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-9373f0a8d417 -j DOCKER
-A FORWARD -i br-9373f0a8d417 ! -o br-9373f0a8d417 -j ACCEPT
-A FORWARD -i br-9373f0a8d417 -o br-9373f0a8d417 -j ACCEPT
-A DOCKER-USER -j RETURN

Выша проблема надуманна. Вот стандартные правили докера. В них разрешается выход наружу, общение внутри бриджа между сервисами. Добавить ПОСЛЕ правил для запретов достаточно. Разрешений заходить внутрь тут не вижу.

Если хотите добавить правила спереди, то добавьте эти правила в цепочку DOCKER-USER . Она выполнится перед этими ацептами. Докер не перетирает эту цепочку при рестарте.

Используй команду iptables-save - в ней видно что происходит. Вместе с iptables-restore эти команды удобны для хранения и накатывания "своих" правил.

→ Ссылка