Материал подготовлен командой Simple-Server для администраторов VPS и выделенных серверов. Команды и пути проверяйте на тестовой машине перед production.
Кратко о задаче
Межсетевой экран (брандмауэр/файрвол) — это программа для обеспечения контроля доступа на сетевом уровне. Основываясь на прописанных правилах, брандмауэр определяет, какие устройства имеют доступ к участкам сети. Иными словами, какой-то трафик разрешить, остальное заблокировать. В Linux эти функции выполняет программа netfilter, встроенная в ядро.
Как мы уже поняли, netfilter работает на уровне ядра. Для настройки файрвола нужны инструменты в пользовательском пространстве. В качестве фреймворков для управления netfilter используются ip_tables/nf_tables, реализованные в виде модулей ядра. А поверх них на уровне пользователя работают соответственно или iptables (одноименная утилита командной строки), или nft.
Опытные администраторы знают, что вручную прописывать правила для iptables или nft не так просто. Особенно, когда нужно настроить крупную сеть или перенести правила на другую систему. Поэтому были придуманы более дружелюбные и многофункциональные надстройки. Например, в Ubuntu такой надстройкой является инструмент с говорящим названием ufw (Uncomplicated Firewall). А в семействе RedHat дистрибутивов (CentOS, Alma, Fedora, RHEL, OpenSUSE, SUSE Linux Enterprise) — firewalld.
Для управления firewalld существует две программы: firewall-cmd для работы в терминале и графический firewall-config. В этом материале мы будем**** работать с firewalld в CentOS и использовать firewall-cmd.
Арендовать собственный сервер для тестирования и экспериментов можно здесь.
Проверим состояние сервиса:
sudo systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-28 11:11:29 MSK; 2min 24s ago
Docs: man:firewalld(1)
Main PID: 484 (firewalld)
CGroup: /system.slice/firewalld.service
└─484 /usr/bin/python2 -Es /usr/sbin/firewalld --nofork --nopidВ RHEL-based дистрибутивах firewalld предустановлен, однако никто не мешает поставить его вручную на вашем любимом дистрибутиве. Просто скачайте пакет и запустите сервис. Например, в Ubuntu это делается так:
sudo apt install firewalld
sudo systemctl enable firewalld --nowТолько не забудьте отключить ufw — использовать одновременно два фронтенда для iptables/nftables не рекомендуется.
Узнаем активные правила (что разрешено и запрещено, к чему относится разрешения и т.д.):
sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: dhcpv6-client ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:В выводе команды мы видим много различных параметров. Разберем их по порядку.
Поле ports в выводе предыдущей команды показывает порты, по которым разрешено соединение. Продемонстрируем настройку на примере: поменяем прослушиваемый порт демона OpenSSH с 22-го на 3333-й (файл /etc/ssh/sshd_config):
Port 3333
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
sudo systemctl restart sshdВыведем порты, прослушиваемые sshd:
sudo ss -nl4p | grep sshd
tcp LISTEN 0 128 *:3333 *:* users:(("sshd",pid=7602,fd=3))Видим, что теперь прослушивается порт 3333. Текущий сеанс не прервался, но если попробуем заново подключиться по стандартному или новому порту, то ничего не получится:
ssh: connect to host 37.46.131.83 port 22: Connection refused
ssh user1@37.46.131.83 -p 3333
ssh: connect to host 37.46.131.83 port 3333: No route to hostНеобходимо добавить разрешающее правило в firewalld, позволяющее подключаться по 3333/tcp:
sudo firewall-cmd --add-port=3333/tcp
sudo firewall-cmd --add-port=3333/tcp --permanent
sudo firewall-cmd --reloadВ первом случае изменения активно только в текущем runtime, и при перезапуске машины или сервиса все сбрасывается. Во втором случае изменение делается постоянным. Ключ --permanent указывает, что меняются настройки, а не рантайм, поэтому нужно перезапустить файрвол (опция --reload).
Проверим, какие порты теперь разрешены:
sudo firewall-cmd --list-ports
ssh user1@37.46.131.83 -p 3333
user1@37.46.131.83's password:
Last login: Thu Apr 28 11:13:39 2022Внимательный читатель задастся вопросом, как мы могли подключаться по SSH раньше, ведь вначале поле ports в выводе политик было пустым. Дело в том, что настройки были заданы с помощью описания сервисов.
Сервисы в firewalld представляют собой описания служб, делающие настройку более удобной и централизованной. Посмотрим текущие сервисы и информацию о них:
sudo firewall-cmd --list-services
sudo firewall-cmd --info-service=ssh
ssh
ports: 22/tcp
protocols:
source-ports:
modules:
destination:Заметим, что в SSH все также 22-й порт. Дело в том, что собственные параметры демонов никак не связаны с их описаниями в firewalld. Попробуем убрать стандартный порт и добавить 3333-й в описание сервиса ssh (не забудем удалить порт 3333/tcp из политик):
sudo firewall-cmd --service=ssh --remove-port=22/tcp --permanent
sudo firewall-cmd --remove-port=3333/tcp --permanent
sudo firewall-cmd --service=ssh --add-port=3333/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --info-service=ssh
ssh
ports: 3333/tcp
protocols:
source-ports:
modules:
destination:Попробуем удалить и добавить какой-нибудь сервис:
sudo firewall-cmd --list-services
sudo firewall-cmd --remove-service=dhcpv6-client
sudo firewall-cmd --add-service=mysql
sudo firewall-cmd --runtime-to-permanent
sudo firewall-cmd --list-servicesОпция --runtime-to-permanent делаем рантайм постоянными — можно не указывать --permanent после каждой команды, а выполнить набор команд и только после этого сделать настройки постоянными (не всегда работает, так как некоторые команды требуют ключ --permanent).
Файлы с предопределенными сервисами расположены по пути /lib/firewalld/services. Выведем их список:
sudo firewall-cmd --get-services
RH-Satellite-6 RH-Satellite-6-capsule amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kerberos kibana klogin kpasswd kprop kshell ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nfs nfs3 nmea-0183 nrpe ntp nut ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster quassel radius redis rpc-bind rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync squid ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-serverВы можете создавать собственные сервисы. Для этого создайте файл в формате xml в директории /etc/firewalld/services. Для удобства можно скопировать какой-нибудь конфиг из /etc/firewalld/services и внести соответствующие изменения. После перезапустите файрвол ключом --reload.
ICMP, протоколы и таргеты
В выводе --list-all есть следующие любопытные поля:
sudo firewall-cmd --list-all | grep -E '(target|icmp|protocols)'
target: default
icmp-block-inversion: no
protocols:
icmp-blocks:В firewalld можно настраивать не только сервисы и порты, но и протоколы. Допустим, мы настраиваем файрвол на маршрутизаторе. Тогда имеет смысл указать перечень разрешенных протоколов. Для иллюстрации разрешим протокол динамической маршрутизации OSPF:
sudo firewall-cmd --add-protocol=ospf
sudo firewall-cmd --list-protocolsПоля icmp-blocks и icmp-blocks-inversion содержат параметры для протокола ICMP. Его функции — тестирование сети и оповещение об ошибках. Программы ping и traceroute используют его в своей работе.
С помощью icmp-blocks можно заблокировать определенные ICMP-сообщения. Icmp-blocks-inversion делает инверсию логики — перечисленные типы сообщений становятся разрешенными, остальные блокируются. Такой функционал можно использовать, чтобы скрыть информацию о сети, так как многие механизмы сканирования используют ICMP. Давайте протестируем блокировку с помощью утилиты ping.
Запрещаем все типы ICMP-сообщений (так как в icmp-block ничего не перечислено, все сообщения становятся запрещенными):
sudo firewall-cmd --add-icmp-block-inversionТеперь попробуем пропинговать сервер:
PING 37.46.131.83 (37.46.131.83) 56(84) bytes of data.
From 37.46.131.83 icmp_seq=1 Destination Host Prohibited
From 37.46.131.83 icmp_seq=2 Destination Host Prohibited
From 37.46.131.83 icmp_seq=3 Destination Host Prohibited
--- 37.46.131.83 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2004msМашина не пингуется. Такой метод часто используют провайдеры, чтобы скрыть адреса маршрутизаторов. Однако по ошибкам понятно, что на целевых устройствах пакеты фильтруются брандмауэром. Чтобы скрыть компьютер, нужно использовать таргеты.
Таргет — это действие, которое необходимо сделать с пакетом, если сработало какое-то из правил. Наиболее используемые: DROP, ACCEPT, REJECT. В примере выше таргетом был REJECT, т.е. возвращалась причина ошибки. Чтобы выбросить пакет, ничего не отправляя, нужно использовать DROP:
sudo firewall-cmd --set-target=DROP --permanent
sudo firewall-cmd --reload
PING 37.46.131.83 (37.46.131.83) 56(84) bytes of data.
^C
--- 37.46.131.83 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2050msПри работе с firewalld часто используются зоны. На машине может иметься несколько интерфейсов. Допустим, один из них «смотрит» в интернет, другой — в LAN, третий — в dmz. Разные сети имеют разный уровень доверия, соответственно, поступающий из них трафик должен контролироваться различными правилами брандмауэра. Для этого в firewalld используются зоны — наборы правил, применяемых к различным фрагментам сети.
Все действия выше мы применяли для зоны public (по умолчанию):
sudo firewall-cmd --get-default-zoneВ firewalld изначально прописаны несколько зон. Однако можно создавать и свои зоны. Выведем список имеющихся зон:
sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted workОпция --zone позволяет устанавливать и смотреть правила для конкретной зоны (без него, все применяется к зоне по умолчанию). Посмотрим политики для зоны drop:
sudo firewall-cmd --list-all --zone=drop
drop
target: DROP
icmp-block-inversion: no
interfaces:
sources:
services:
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:В нашем случае единственный интерфейс eth0, через который осуществляется доступ в интернет, смотрит в зону public. Значит для входящего трафика применяются политики зоны public. Для добавления интерфейса в другую зону используется ключ --change-interface. Переместим наш eth0 в зону home:
sudo firewall-cmd --change-interface=eth0 --zone=home
sudo firewall-cmd --list-interfaces --zone=homeМожет возникнуть задача, когда необходимо настроить правила не для всего входящего на интерфейс трафика, а для конкретного адреса. Делается это так:
sudo firewall-cmd --zone=drop --add-source=192.168.3.1
sudo firewall-cmd --zone=drop --list-all
drop (active)
target: DROP
icmp-block-inversion: no
interfaces:
sources: 192.168.3.1
services:
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:Теперь, даже если пакеты с адреса 192.168.3.1 придут на интерфейс eth0, то будут применяться правила не для зоны, в которой расположен интерфейс, а для заданной нами вручную зоны (drop).
NAT — это технология трансляции интернет-адресов. Существует два вида NAT — source и destination. В первом случае маршрутизатор подменяет домашние IP-адреса на свой внешний, т.е. изменяется адрес отправителя (отсюда и название source). В Linux это называется маскарадингом (masquerade). Во втором случае заменяется адрес получателя (проброс портов). Например, на порт маршрутизатора приходит пакет, а роутер пересылается пакет на какой-нибудь другой порт.
Допустим, имеется задача настроить файрвол на роутере. Разрешим source nat:
sudo firewall-cmd --add-masquerade
sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: mysql ssh
ports:
protocols:
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:Проброс портов на машине:
sudo firewall-cmd --add-forward-port=port=3333:proto=tcp:toport=22
sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: mysql ssh
ports:
protocols:
masquerade: yes
forward-ports: port=3333:proto=tcp:toport=22:toaddr=
source-ports:
icmp-blocks:
rich rules:Еще вы можете заметить опцию source-ports. В firewalld можно разрешать определенные исходящие порты, однако используется это редко, так как обычно в качестве source портов выступают динамические 5-значные порты.
Мы разобрали, как в firewalld использовать разные правила к разным областям сети (интерфейсы, IP адреса). Но иногда возникает задача создания точечных правил: разрешить подключение с конкретного адреса на конкретный порт, используя такие-то протоколы и т.д. Конечно, можно создать собственную зону, однако лучше использовать rich-rules.
У rich-rules в firewall centos отдельный синтаксис, подробности можно посмотреть в манах:
man firewalld.richlanguageТам же есть множество примеров:
Добавить вручную прописанное правило:
sudo firewall-cmd --add-rich-rule=’правило’Нужен сервер для практики? Арендуйте VPS/VDS в России — root-доступ, NVMe, DDoS-защита и поддержка 24/7.