Настройке межсетевого экрана при помощи iptables в Linux посвящена не одна статья, и, так как тема популярна, вероятно, будет написано множество других. Для простых конфигураций все достаточно легко, но вот если сети сложные, а компьютеров много, то дело уже не кажется таким простым. А перенос правил в другие системы не всегда прозрачен.
 

Iptables и другие

Проект iptables, разработанный Расти Расселом (Rusty Russell) в 1999 году для управления netfilter и заменивший в ядре 2.4 ipchains и ряд других инструментов вроде ipnatctl, предлагает более расширяемый способ фильтрации пакетов, обеспечивающий сисадмину больший контроль при упрощении самих правил. Так, в ipchains нужно было создавать правило в каждой цепочке, прослеживая весь маршрут пакета, теперь достаточно одного. Появление модулей позволяло очень просто расширять возможности. В процессе развития проекта iptables был портирован для IPv6 (в 2011 году, ip6tables), добавлялись дополнительные модули (ULOG, nf_conntrack), он научился производить разные манипуляции с пакетами, классифицировать трафик (до седьмого уровня OSI), балансировать нагрузку и многое другое. С ростом количества функций усложнились и настройки. При этом, даже несмотря на некоторую унификацию, каждое расширение имеет свой синтаксис, одни поддерживают диапазоны, отрицание, префиксы, другие — нет. Поначалу каждое изменение правил требовало полного перезапуска брандмауэра, включая выгрузку модулей, что приводило к разрыву установленных соединений. Сейчас такой проблемы нет.

Для простых случаев настройка при помощи iptables — дело нехитрое, но в сложных сетях управлять большим количеством правил становится тяжело; чтобы изучить все настройки и понять, как оно работает, нужно потратить время. Трудно с ходу разобраться, что делают все цепочки, правила начинают повторяться, их становится сложно обслуживать, обновлять и переносить на другие системы.

Неудивительно, что для решения этих проблем были придуманы разные надстройки. Так, в Ubuntu для простой настройки правил используется ufw (Uncomplicated Firewall — несложный файрвол). Например, чтобы открыть доступ к SSH-порту, достаточно ввести

$ sudo ufw allow 22

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

Еще один известный проект, позволяющий легко поддерживать сложные правила, — FERM (for Easy Rule Making). В FERM все правила хранятся в одном файле, который легко читается, редактируется и загружается одной командой. Такой файл просто переносить между компьютерами. Сами правила группируются в блоки, содержат переменные, списки, что позволяет задать те же настройки в более коротком и понятном виде. Итоговый размер правил FERM раза в три меньше аналогичных для iptables. Например, запрещаем все соединения, кроме HTTP, SSH и FTP.

chain INPUT {
    policy DROP;
    mod state state (RELATED ESTABLISHED)  ACCEPT;
    proto tcp dport (http ssh ftp)  ACCEPT;
}

Под капотом FERM находится обычный Perl-скрипт, который конвертирует конфигурационные файлы в правила iptables.

В Fedora 18 был анонсирован демон firewalld, ставший официальным приложением для управления настройками netfilter в RHEL 7 / CentOS 7. Последние становятся все популярнее на VDS, а значит, придется столкнуться с их особенностями.

 

Возможности firewalld

Firewalld запускается как демон, новые правила добавляются без перезапуска и без сброса установленного файрвола. Изменения в конфигурации могут быть сделаны в любое время и применяются мгновенно: сохранять или применять изменения не требуется. Поддерживается IPv4, IPv6, автоматическая загрузка модулей ядра и сетевые зоны, определяющие уровень доверия соединений. Предоставляется простой интерфейс добавления правил для служб и приложений, белый список приложений, имеющих право менять правила. В настоящее время такую возможность поддерживает libvirt, Docker, fail2ban, Puppet, скрипт установки Virtuozzo и многие другие проекты. В репозитории YUM уже есть пакеты fail2ban-firewalld и puppet-firewalld, поэтому подключить их можно одной командой.

Firewalld предоставляет информацию о текущих настройках брандмауэра через D-Bus API, а также принимает изменения через D-Bus с использованием методов аутентификации PolicyKit. В качестве бэкенда используются iptables, ip6tables, ebtables, ipset и планируется nftables. Но сами правила, созданные непосредственно этими утилитами, firewalld не может разобрать, поэтому оба метода использовать нельзя.

Управление производится при помощи утилит командной строки firewall-cmd или графической firewall-config, позволяющей настроить все правила в удобной среде. Для помощи в миграции текущих правил iptables на firewalld используется утилита firewall-offline-cmd, по умолчанию считывающая /etc/sysconfig/system-config-firewall. В последних релизах появилась утилита firewallctl, имеющая простой синтаксис и позволяющая получать информацию о состоянии службы, конфигурации брандмауэра и изменять правила.

Графическая firewall-config поддерживает firewalld
Графическая firewall-config поддерживает firewalld

Параметры firewall-cmd
Параметры firewall-cmd

Смотрим статус:

# systemctl status firewalld 
# firewall-cmd --state
running

Разрешить соединение на определенный порт очень просто:

# firewall-cmd --permanent --add-port=22/tcp

Чтобы любые изменения вступили в силу, всегда после правок должна быть запущена команда

# firewall-cmd --reload

Для удаления порта из правил используется параметр --remove-port:

# firewall-cmd --remove-port=22/tcp

Вообще, многие команды --add-* имеют значения для проверки статуса --query-*, --list-* — список, изменения --change-* или удаления --remove соответствующего значения. Для краткости на этом не будем дальше заострять внимание. После релоада правил проверяем:

# firewall-cmd --list-ports

В firewalld предусмотрен режим, позволяющий одной командой заблокировать все соединения:

# firewall-cmd --panic-on

Для проверки, в каком режиме находится файрвол, есть специальный ключ:

# firewall-cmd --query-panic 

Отключается panic mode:

# firewall-cmd --panic-off

В firewalld необязательно знать, какой порт привязан к сервису, достаточно указать название сервиса. Все остальное утилита возьмет на себя.

После установки firewalld знает настройки более 50 сервисов, получаем их список.

# firewall-cmd --get-services

Разрешим подключение к HTTP:

# firewall-cmd --add-service=http

Используя фигурные скобки, можно задавать сразу несколько сервисов. Информация по настройкам сервисов доступна при помощи

# firewall-cmd --info-service=http

Firewalld хранит все настройки в XML-файлах в каталогах в /usr/lib/firewalld. В частности, сервисы лежат в services. Внутри файла описание: название, протокол и порт.

<?xml version="1.0" encoding="utf-8"?>
<service>
    <short>MySQL</short>
    <description>MySQL Database Server</description>
    <port protocol="tcp" port="3600"/>
</service>

Это каталог системный, и менять там ничего нельзя. Если нужно переопределить настройки или создать свой сервис, то копируем любой файл в качестве шаблона в /etc/firewalld/services, правим под свои условия и применяем настройки.

Для настройки ICMP используется отдельный набор правил. Получаем список поддерживаемых типов ICMP:

# firewall-cmd --get-icmptypes

Проверяем статус:

# firewall-cmd --zone=public --query-icmp-block=echo-reply
# firewall-cmd --zone=public --add-icmp-block=echo-reply    


Все настройки firewalld хранит в XML-файлах
Все настройки firewalld хранит в XML-файлах

Firewalld знает о почти 50 сервисах
Firewalld знает о почти 50 сервисах

 

Управление зонами

Для определения уровня доверия сетевому соединению в firewalld используются зоны. Зона может содержать несколько сетевых подключений, но сетевое соединение может входить только в одну зону. Список всех зон получаем командой firewall-cmd --get-zones.

Получаем список зон
Получаем список зон

После установки создается девять зон, в зависимости от назначения может быть использована одна или несколько зон:

  • trusted — все сетевые соединения разрешены;
  • work/home/internal — зоны похожи по настройкам, отличаются назначением. Устанавливается максимальное доверие к компьютерам в сети, разрешается устанавливать только конкретные входящие соединения (по умолчанию SSH и DHCPv6 client, в home и internal плюс MDNS и Samba client);
  • dmz — для компьютеров, находящихся в демилитаризованной зоне, доступные из Сети и с ограниченным доступом к внутренней сети. Разрешаются только указанные входящие соединения (по умолчанию SSH);
  • external — правило, подходящее для роутеров, для использования во внешних сетях с разрешенным маскарадингом, с максимальным недоверием и четко установленными разрешенными входящими соединениями (по умолчанию SSH);
  • public — для использования в общественных местах, с максимальным недоверием к другим компьютерам, разрешены только конкретные входящие соединения (по умолчанию SSH и DHCPv6 client);
  • block — входящие сетевые соединения отклоняются с icmp-host-prohibited сообщением, разрешены только соединения, инициированные в этой системе;
  • drop — разрешаются только исходящие соединения, все входящие блокируются.

Описания зон также представлены в XML-файлах в /usr/lib/firewalld/zones.

После установки системы обычно используется зона public. Если имеющихся зон недостаточно, то можно создавать новые зоны при помощи

# firewall-cmd --permanent --new-zone=zone_name
Настройки зон по умолчанию
Настройки зон по умолчанию

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

# firewall-cmd --get-default-zone

Теперь — какие зоны сейчас активны и какие интерфейсы к ним привязаны.

# firewall-cmd --get-active-zones

Также можем получить обратную информацию — к какой зоне привязан интерфейс.

# firewall-cmd --get-zone-of-interface=eno1

Смотрим настройки зоны (сервисы, порты, протоколы...).

# firewall-cmd --zone=public --list-all
# firewall-cmd --zone=public --list-services

Если параметр пуст, то это значит, что настройки не установлены. При необходимости переназначаем интерфейс зоне:

# firewall-cmd --zone=home --add-interface=eno1 --permanent

Если сейчас проверить вывод firewall-cmd --zone=public --list-all, то увидим, что из списка установок пропал сетевой интерфейс. Разрешим подключение сервиса:

# firewall-cmd --zone=home --add-service=openvpn --permanent

Удаляется он так же:

# firewall-cmd --zone=home --remove-service=openvpn --permanent

К зонам можно привязывать и другие источники, определяемые по MAC, отдельному IP или адресу сети. Пакет, пришедший из такого источника, будет обрабатываться по правилам зоны.

# firewall-cmd --permanent --zone=trusted --add-source=192.168.1.0/24    

Список всех source смотрим при помощи --zone=trusted --list-sources. NAT, позволяющий нескольким компьютерам подключаться к сети, в firewalld включается одной командой. Смотрим текущие настройки маскарадинга:

# firewall-cmd --zone=external --query-masquerade

Если в ответ получим no, то включаем:

# firewall-cmd --zone=external --add-masquerade

Это все. Для доступа извне настроим форвардинг порта в один из компьютеров. Например, нам нужен доступ по SSH к внутреннему серверу:

# firewall-cmd --zone=external --add-forward-port=port=22:proto=tcp:toport=22:toaddr=192.168.1.100

Проверяем:

# firewall-cmd --zone=external --list-all

Удаляется правило форвардинга при помощи --remove-forward-port.

 

Сложные правила

Для отдельного ПК или небольших сетей базовых возможностей вполне хватает, для настройки сложных правил в firewalld изначально предлагался так называемый direct-синтаксис, чуть позже появился собственный язык Rich Language. В первом варианте достаточно знать синтаксис iptables, рекомендуется использовать в крайнем случае, так как правила не сохраняются после перезагрузки.

Синтаксис direct правила такой:

# firewall-cmd [--permanent] --direct --add-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>

Позиция полностью совпадает с синтаксисом iptables. Получаем текущие установки:

# firewall-cmd --direct --get-chains ipv4 filter
# firewall-cmd --direct --get-rules ipv4 filter input

Добавляем правило, разрешающее соединение по 25-му порту:

# firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -m tcp -p tcp --dport 25 -j ACCEPT

Пробросим соединение по 22-му на другой сервер:

# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i eno1 -o eno2 -p tcp --dport 22 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT

Проверяем:

# firewall-cmd --direct --get-all-rules

Rich Language позволяет записывать сложные правила в более удобном для понимания виде. В правиле можно указывать любые параметры, характеризующие пакет: источник, назначение, сервис, порт, протокол, маскарадинг, журналирование, аудит и действие. Например, разрешим подсети соединяться по HTTP и добавляем аудит:

# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.0.0/24" service name="http" audit limit value="1/m" accept

Большой плюс Rich Language в том, что все параметры можно описать в XML в файле зоны. Формат файла очень простой и повторяет названия параметров:

<rule>
    <service name="ssh"/>
    <accept/>
</rule> 

Настройка файрвола — дело привычки. Часто удобнее вбить команду, которой пользуешься уже не один год, чем осваивать новую утилиту. Поэтому иногда все-таки хочется вернуть классический инструмент. Это не проблема. Iptables в CentOS 7 не ставится, поэтому его нужно вернуть:

# yum install -y iptables-services

Чтобы не настраивать все повторно, лучше сохранить текущие правила, сгенерированные firewalld.

# iptables-save > /etc/sysconfig/iptables
# ip6tables-save > /etc/sysconfig/ip6tables

Останавливаем firewalld и запускаем iptables:

# systemctl stop firewalld && systemctl disable firewalld
# systemctl start iptables && systemctl enable iptables
# systemctl start ip6tables && systemctl enable ip6tables

Проверяем текущие правила:

# iptables -L
# iptables -S

Запрещаем автозапуск firewalld при загрузке ОС:

# systemctl disable firewalld

 

Выводы

Как видишь, ничего сложного! Firewalld очень упрощает установки, особенно если учесть, что настройки легко перенести.

1 комментарий

  1. Аватар

    Quantos

    19.03.2017 в 16:28

    Все руки никак не доходили про этот инструмент почитать. У самого половина серверов под Centos7, и я по привычке юзал IPTABLES )
    Теперь жизнь станет немного легче, автору спасибо!

Оставить мнение