Базовые правила Iptables для сервера Ubuntu
Ubuntu, VPS | Комментировать запись
Правильно настроенный брандмауэр – один из основных аспектов безопасности сервера. Брандмауэр позволяет выбрать для сервера индивидуальные правила и политику, которые ограничат трафик. Брандмауэры, такие как iptables, позволяют определять структурные рамки, в которых будут применяться эти правила.
Данное руководство поможет вам составить список базовых правил брандмауэра для сервера Ubuntu. Такой список легко расширить, и в дальнейшем вы сможете использовать этот шаблон для создания более сложных правил.
Требования
Вам понадобится сервер Ubuntu с пользователем sudo. Подробно настройка описана в этом мануале (раздел 4 по настройке брандмауэра можно пропустить).
Также рекомендуем просмотреть политики брандмауэра, которые вы хотите применить. Ознакомьтесь с мануалом Как выбрать эффективную политику брандмауэра, чтобы понять, что следует учитывать.
Установка iptables-persistent
Начнем с обновления локального кеша пакетов:
sudo apt update
Теперь нужно установить пакет iptables-persistent, который позволяет сохранять наборы правил брандмауэра и автоматически использовать их в дальнейшем:
sudo apt install iptables-persistent
Во время установки пакет предложит вам сохранить текущий набор правил брандмауэра. Чтобы сделать это, выберите yes. Обратите внимание, что нужно выполнить команду netfilter-persistent для запуска службы брандмауэра iptables. Потом мы отредактируем сгенерированные файлы правил.
Примечание: протоколы IPv4 и IPv6
Сейчас мы коротко разберем IPv4 и IPv6. Команда iptables обрабатывает только трафик IPv4. Для обработки трафика IPv6 существует отдельный инструмент, ip6tables. Правила для IPv4 и IPv6 хранятся в отдельных таблицах и цепочках. Пакет iptables-persistent записывает правила IPv4 в /etc/iptables/rules.v4, а правила IPv6 – в /etc/iptables/rules.v6.
Данное руководство предназначено только для IPv4. Если вы не используете IPv6, рекомендуем полностью заблокировать такой доступ. Как это сделать, мы покажем позже.
Базовая политика брандмауэра
Чтобы быстро настроить и внедрить брандмауэр, вы можете отредактировать файл правил и вставить в него готовую политику вручную. Также правила можно добавить в файл с помощью команды iptables; об этом можно узнать далее.
Чтобы настроить политику брандмауэра, отредактируйте файлы /etc/iptables/rules.v4 и /etc/iptables/rules.v6. Откройте файл rules.v4 в любом удобном текстовом редакторе. Мы будем использовать nano:
sudo nano /etc/iptables/rules.v4
Его содержимое выглядит так:
# Generated by iptables-save v1.8.4 on Tue Mar 1 19:03:10 2022 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Tue Mar 1 19:03:10 2022
Замените его таким набором правил:
*filter # Allow all outgoing, but drop incoming and forwarding packets by default :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Custom per-protocol chains :UDP - [0:0] :TCP - [0:0] :ICMP - [0:0] # Acceptable UDP traffic # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT # Acceptable ICMP traffic # Boilerplate acceptance policy -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -i lo -j ACCEPT # Drop invalid packets -A INPUT -m conntrack --ctstate INVALID -j DROP # Pass traffic to protocol-specific chains ## Only allow new connections (established and related should already be handled) ## For TCP, additionally only allow new SYN packets since that is the only valid ## method for establishing a new TCP connection -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP # Reject anything that's fallen through to this point ## Try to be protocol-specific w/ rejection message -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable # Commit the changes COMMIT *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT *security :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT
Сохраните и закройте файл. Если используете nano: нажмите CTRL + X, затем Y и ENTER.
Проверьте ошибки в файле с помощью следующей команды. Если вы обнаружили их, обязательно исправьте их.
sudo iptables-restore -t /etc/iptables/rules.v4
Затем откройте файл /etc/iptables/rules.v6, чтобы отредактировать правила IPv6:
sudo nano /etc/iptables/rules.v6
Его содержимое будет выглядеть так:
# Generated by ip6tables-save v1.8.4 on Tue Mar 1 19:03:10 2022 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Tue Mar 1 19:03:10 2022
Заблокируйте весь трафик IPv6, заменив набор правил этого файла следующими правилами:
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] COMMIT *raw :PREROUTING DROP [0:0] :OUTPUT DROP [0:0] COMMIT *nat :PREROUTING DROP [0:0] :INPUT DROP [0:0] :OUTPUT DROP [0:0] :POSTROUTING DROP [0:0] COMMIT *security :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] COMMIT *mangle :PREROUTING DROP [0:0] :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] :POSTROUTING DROP [0:0] COMMIT
Сохраните и закройте файл.
С помощью команды ip6tables-restore с флагом -t проверьте файл на наличие ошибок:
sudo ip6tables-restore -t /etc/iptables/rules.v6
Если файлы правил не содержат ошибок, их можно применить с помощью команды:
sudo service netfilter-persistent reload
Вывод будет следующим:
* Loading netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start [ OK ]
Эта команда обновит списки правил брандмауэра. Чтобы убедиться в том, что теперь iptables использует новые правила, запросите текущие наборы сначала для IPv4:
sudo iptables -S
Получаем такой вывод:
-P INPUT DROP -P FORWARD DROP -P OUTPUT ACCEPT -N ICMP -N TCP -N UDP -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DRO -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable -A TCP -p tcp -m tcp --dport 22 -j ACCEPT
Затем запросите текущие наборы правил для IPv6:
sudo ip6tables -S
Получим вывод:
-P INPUT DROP -P FORWARD DROP -P OUTPUT DROP
Эти наборы правил будут применяться после каждой перезагрузки сервера. Убедитесь, что вы можете получить доступ к серверу и что остальной доступ заблокирован брандмауэром.
Разбор общей стратегии брандмауэра
Базовые правила брандмауэра, которые приведены выше, создают расширяемый шаблон. Вы можете легко добавить или удалить правила из этого набора. Трафик IPv4 в основном представлен цепочкой INPUT в таблице filter. Эта цепочка будет обрабатывать все пакеты, предназначенные для сервера. Также текущие правила разрешают весь исходящий трафик и блокируют пересылку пакетов (она уместна только в том случае, если этот сервер используется в качестве маршрутизатора для других хостов).
В целом такой набор правил будет запрещать входящий трафик по умолчанию. После этого нужно создать правила для сервисов и типов трафика, которые нужно исключить из этой политики.
В главную цепочку INPUT были помещены общие правила для трафика, который всегда нужно обрабатывать одним и тем же образом. Например, брандмауэр будет всегда блокировать пакеты, которые считаются недействительными, и будет пропускать трафик на локальный loopback интерфейс и данные, связанные с установленным соединением.
После этого брандмауэр выбирает трафик согласно используемому протоколу и передаёт его цепочке, предназначенной для этого протокола. Такие цепочки предназначены для хранения правил, которые пропускают трафик для конкретных сервисов. В этом примере единственным сервисом, чей трафик пропустит брандмауэр, является SSH в цепочке TCP. В дальнейшем вы можете добавить исключения для других сервисов, например, для серверов HTTP(S). Эти цепочки составляют основу настройки брандмауэра.
Любой трафик, который не соответствует общим правилам или правилам службы в цепочках для конкретных протоколов, обрабатывается несколькими последними правилами в цепочке INPUT. Мы установили политику по умолчанию DROP для нашего брандмауэра, которая будет блокировать пакеты, которые не соответствуют нашим правилам. Однако правила в конце цепочки INPUT отклоняют пакеты и отправляют клиенту сообщение, которое имитирует реакцию сервера, если на этом порту не запущена служба.
Что касается трафика IPv6, то он полностью заблокирован. Этот сервер не использует протокол IPv6, потому гораздо безопаснее заблокировать трафик IPv6.
Настройка брандмауэра с помощью команды iptables
Теперь у вас есть общее представление о политике брандмауэра. Данный раздел научит вас добавлять правила в файл с помощью команды iptables. В результате файл правил будет выглядеть точно так же, как созданный вручную файл в предыдущем разделе. Команда iptables активирует правило сразу же после его добавления, потому порядок добавления правил очень важен. Правила, которые сбрасывают пакеты, нужно добавить в конце.
Сброс текущих правил брандмауэра
Для начала сбросьте текущие правила, чтобы мы рассмотрели создание политик из командной строки. Выполните команду:
sudo service netfilter-persistent flush
Теперь убедитесь, что правила сброшены:
sudo iptables -S
Таблица filter не должна содержать никаких правил, а политикой по умолчанию для всех цепочек будет ACCEPT.
-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT
Создание цепочек для протоколов
Теперь определим цепочки правил для конкретных протоколов. В них будут храниться правила, которые создают исключения из политики запрета для служб, которые вы хотите раскрыть. Создайте цепочки для протокола UDP:
sudo iptables -N UDP
Затем еще один для TCP:
sudo iptables -N TCP
И еще один для ICMP:
sudo iptables -N ICMP
После этого можно добавить правило для трафика SSH. SSH использует TCP, потому нужно добавить правило, разрешающее этот трафик на порт 22, в цепочку TCP.
sudo iptables -A TCP -p tcp --dport 22 -j ACCEPT
Чтобы добавить другие сервисы TCP, используйте эту же команду, изменив только номер порта.
Общие правила приёма и сброса трафика
Общие правила для управления трафиком нужно добавить в цепочку INPUT, в которой фильтруется весь входящий трафик. Эти правила будут принимать локальный трафик и трафик, связанный с проверенными соединениями, и сбрасывать все недействительные пакеты.
Создайте исключение, которое будет принимать трафик, относящийся к установленным соединениям:
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Это правило использует расширение conntrack, которое обеспечивает внутреннее отслеживание и предоставляет брандмауэру iptables контекст, на основании которого он сможет воспринимать пакеты как часть более крупных соединений, а не как поток отдельных, несвязанных пакетов. TCP представляет собой протокол, ориентированный на соединения, поэтому установленные соединения достаточно хорошо определены. UDP и другие протоколы без установления соединения воспринимают источник исходного пакета как цель ответного пакета и наоборот; потому связанные с установленным соединением пакеты будут восприниматься как новое соединение, инициированное в связи с этим существующим соединением. Классическим примером здесь является соединение передачи данных FTP.
Также нужно разрешить весь трафик, исходящий от локального loopback интерфейса. Это трафик, сгенерированный сервером и предназначенный для сервера. С его помощью сервисы могут взаимодействовать друг с другом.
sudo iptables -A INPUT -i lo -j ACCEPT
В завершение нужно заблокировать все недействительные пакеты. Пакеты могут быть недействительными по нескольким причинам: они могут относиться к несуществующим соединениям, они могут быть предназначены для несуществующих интерфейсов, адресов или портов или же просто использовать неправильный формат. В любом случае, сервер должен сбрасывать такие пакеты, поскольку он не может правильно обработать их, и они могут быть опасны:
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
Настройка цепочек iptables
Итак, в настройках брандмауэра появилась цепочка INPUT и несколько специальных правил для поддержки трафика протоколов. Однако на данный момент весь трафик поступает в цепочку INPUT и не попадает в специальные цепочки правил для протоколов.
Чтобы трафик передавался в ту или иную цепочку, нужно настроить брандмауэр для передачи пакетов согласно типу протокола. При этом пакет будет представлять собой новое соединение (любые установленные или связанные с ним соединения должны быть обработаны ранее). Начнем с UDP-трафика:
sudo iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
Для TCP-пакетов нужно добавить дополнительное требование: такой пакет должен быть пакетом SYN, так как это единственный допустимый тип для начала соединения TCP. Выполните следующую команду для TCP-трафика:
sudo iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
Теперь для трафика ICMP:
sudo iptables -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
Сброс остального трафика
Если пакет не совпал ни с одним правилом из цепочки для протоколов, он вернётся в цепочку INPUT. Любой пакет, достигший этой точки, будет заблокирован брандмауэром.
Чтобы заблокировать такой трафик, используйте цель REJECT, которая отправит клиенту ответное сообщение, которое имитирует реакцию сервера в случае, если клиент пытался отправить пакеты через закрытый порт. Ответ зависит от протокола, используемого клиентом.
К примеру, при попытке передать пакеты через закрытый порт UDP клиент получит сообщение ICMP «port unreachable». Для этого используйте такое правило:
sudo iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
При попытке установить TCP-соединение через закрытый порт клиент получит сообщение RST.
sudo iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
Во всех других случаях можно отправить сообщение ICMP «port unreachable», чтобы сообщить клиенту, что сервер не отвечает на отправленные пакеты.
sudo iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
Настройка политик по умолчанию
Последние три правила в цепочке INPUT будут обрабатывать весь остальной трафик. Установите политику по умолчанию DROP в качестве меры предосторожности.
sudo iptables -P INPUT DROP
Также нужно установить эту политику в цепочке FORWARD, если этот сервер не используется в качестве маршрутизатора для других машин.
sudo iptables -P FORWARD DROP
Важно: Установив политику DROP, вы можете случайно прервать SSH-подключение, если сбросите правила с помощью команды sudo iptables –F. В данном случае сбрасывать правила лучше с помощью команды: sudo netfilter-persistent flush — поскольку эта команда сбросит и политику по умолчанию.
Чтобы блокировать трафик IPv6, можно использовать следующие команды ip6tables, начиная с INPUT:
sudo ip6tables -P INPUT DROP
Затем выполните для FORWARD:
sudo ip6tables -P FORWARD DROP
Завершите настройку политики для OUTPUT:
sudo ip6tables -P OUTPUT DROP
Нужно в точности повторить эти правила.
Сохранение правил iptables
Теперь нужно протестировать правила брандмауэра и убедиться, что он не блокирует трафик необходимых сервисов и протоколов. Убедившись в том, что брандмауэр работает должным образом, вы можете сохранить правила, и они будут автоматически применяться к системе при загрузке сервера.
Чтобы сохранить текущие правила IPv4 и IPv6, введите:
sudo service netfilter-persistent save
Это обновит правила в файлах /etc/iptables/rules.v4 и /etc/iptables/rules.v6 новым набором правил, который вы создали с помощью командной строки.
Заключение
Теперь на вашем сервере есть базовый набор правил брандмауэра, который можно использовать в качестве шаблона для разработки новых наборов.
Читайте также:
- Основы Iptables: общие правила и команды брандмауэра
- Настройка Iptables для защиты трафика между серверами
- Форвардинг портов через шлюз Linux в