Базовая настройка брандмауэра Ubuntu Server 14.04 LTS с помощью iptables

imageКак было справедливо замечено в комментариях к одной из прошлых заметок о конфигурации Ubuntu Server, говоря о вопросах безопасности, стоит обратить отдельное внимание на вопрос настройки брандмауэра на нашем Linux-сервере граничащем с сетью Интернет. В этой заметке мы кратко рассмотрим пример настройки встроенного в ядро Linux брандмауэра Netfilter с помощью интерфейса управления iptables на Ubuntu Server 14.04 LTS. Мы настроим ряд базовых правил брандмауэра, включим на нашем Linux-сервере функцию пересылки трафика (ip forwarding) превратив тем самым его в роутер, а также рассмотрим пару простых примеров настройки пересылки трафика.

Как уже сказано, iptables — это по сути пользовательский интерфейс управления встроенного в ядро Linux брандмауэра Netfilter. iptables оперирует всеми поступающими пакетами на основе правил (Rules), которые группируются в цепочки (Chains). Правила и цепочки хранятся в таблица (Tables).

Посмотрим список текущих правил (без явного указания имени таблицы, используется таблица filter):

sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Как видим, в исходной конфигурации наш сервер содержит в таблице filter три цепочки правил — это INPUT, OUTPUT и FORWARD. В каждой из этих цепочек установлена политика по умолчанию — ACCEPT, то есть принимаются любые пакеты. При этом ни в одной цепочке нет каких-либо правил.

Примерно также картина обстоит и для второй основной таблицы nat.

sudo iptables -L -t nat 
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

Таким образом в конфигурации по умолчанию наш сервер разрешает хождение любого трафика во всех направлениях.

Далее мы рассмотрим простой пример настройки цепочки INPUT исходя из принципа – всё, что не разрешено явно – запрещено, поменяв политику по умолчанию на запрещающую (DROP) и добавив ряд правил разрешающих только определённый трафик.

***

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

1. Правило разрешающее любой входящий трафик на служебный внутренний loopback device. Это может потребоваться для корректной работы разного рода служб и приложений.

sudo iptables -I INPUT 1 -i lo -j ACCEPT

2. Правило для поддержки уже разрешённых ранее и установленных соединений

sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

***

Создадим ряд однотипных правил для запущенных на на нашем сервере служб. Например правила разрешающее входящие TCP-пакеты для подключения к службам SSH-сервера OpenSSH, веб-сервера Apache, прокси-сервера Squid, сервера времени NTPD на сетевом интерфейсе направленном в локальную сеть (eth0):

sudo iptables -A INPUT -p tcp --dport 22 -i eth0 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -i eth0 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -i eth0 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 3128 -i eth0 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 123 -i eth0 -j ACCEPT

Дополнительно создадим правило разрешающее ответы на echo-запросы по протоколу ICPM поступающие на интерфейс внутренней локальной сети нашего Linux-сервера:

sudo iptables -A INPUT -p icmp --icmp-type echo-request -i eth0 -j ACCEPT

***

Меняем политику для всего входящего трафика не попавшего ни под одно правило в цепочке INPUT на запрещающую:

sudo iptables -P INPUT DROP 

То же самое можно сделать и для протокола IPv6. Здесь в качестве интерфейса управления по аналогии с iptables будет выступать ip6tables

sudo ip6tables -P INPUT DROP

***

Проверим что получилось в результате для протокола IPv4:
 

sudo iptables -S
-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 3128 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 123 -j ACCEPT
-A INPUT -i eth0 -p icmp -m icmp --icmp-type 8 -j ACCEPT

А также для протокола IPv6:

sudo ip6tables -S
-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

Тестируем созданные правила и если наблюдаем какие-то проблемы в их работе, — можно выполнить перезагрузку системы для их сброса с первоначальное состояние. Хотя можно восстановить доступ к серверу и без перезагрузки (если остался доступ к консоли), выполнив сброс всех правил цепочки INPUT и вернув её политику по умолчанию на разрешающую:

sudo iptables -F INPUT
sudo iptables -P INPUT ACCEPT

***

Настроенные нами правила вступают в силу сразу после их создания и, как уже отмечено, будут действовать до следующей перезагрузки системы. Чтобы нужные нам правила восстанавливались при последующих загрузках системы, можно использовать разные методы. Один из самых простых – установить пакет iptables-persistent, с помощью которого можно будет сохранять создаваемые нами правила в отдельные конфигурационные файлы, которые в свою очередь будут автоматически загружаться после перезагрузки системы.

sudo apt-get install iptables-persistent

Во время установки пакета нам будет задан вопрос, хотим ли мы сразу сохранить имеющиеся правила IPv4 в конфигурационный файл /etc/iptables/rules.v4

image

Аналогичный вопрос будет задан и по правилам для IPv6, которые будут сохранены в файл /etc/iptables/rules.v6

В дальнейшем, после редактирования правил, для записи изменений в указанные конфигурационные файлы можем передёрнуть службу iptables-persistent:

sudo service iptables-persistent save

* Saving rules...     
* IPv4...
* IPv6... [ OK ]

***

Теперь обговорим реализацию немного другой задачи с помощью брандмауэра Ubuntu Server. Предположим в локальной сети маршрутизация настроена таким образом, что все обращения клиентов сети, выходящие за рамки сегментов маршрутизируемой локальной сети, направляются на сервер подключенный к ресурсам Интернет. В нашем случае это Linux-сервер, который мы используем в частности в качестве прокси-сервера на базе Squid. Чтобы наш Linux-сервер мог выступать в качестве роутера и пересылать сетевые пакеты из локальной сети в Интернет, нам нужно разрешить на нём функцию IP-форвардинга. Сделать это можно например внеся изменения в файл sysctl.conf

sudo nano -Y sh /etc/sysctl.conf

Найдём и раскомментируем две строки (ipv6 только при необходимости):

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

Сохраним файл и применим его изменения в системе:

sudo sysctl -p

По аналогии с цепочкой INPUT, поменяем политику правил брандмауэра по умолчанию в цепочках FORWARD для IPv4 и IPv6 на запрещающую:

sudo iptables -P FORWARD DROP
sudo ip6tables -P FORWARD DROP

Теперь наш сервер готов работать как роутер и заниматься пересылкой трафика отталкиваясь от правил в цепочке FORWARD, которые создадим мы в дальнейшем.

***

Рассмотрим пример, когда нужно явно разрешить пересылку определённого типа трафика. Например есть необходимость пересылки DNS-запросов от двух внутренних DNS-серверов в локальной сети на внешние DNS-сервера в Интернет (например Root-сервера). Допустим IP-адреса внутренних DNS-серверов 10.160.0.253 и 10.160.0.254. Для того, чтобы создать правила разрешающие пересылку DNS-запросов с этих серверов на внешние DNS-сервера в Интернет, выполним 3 блока команд:

1. Разрешаем проброс трафика (для новых и уже установленных соединений) исходящего с IP-адресов внутренних DNS-серверов на порт 53 TCP/UDP (запросы к внешним DNS-серверам):

sudo iptables -A FORWARD -p udp -s 10.160.0.253 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -p tcp -s 10.160.0.253 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT

sudo iptables -A FORWARD -p udp -s 10.160.0.254 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -p tcp -s 10.160.0.254 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT

2. Разрешаем проброс трафика (только для уже установленных соединений) идущий с порта 53 TCP/UDP (с внешних DNS-серверов) на IP-адреса внутренних DNS-серверов (ответы на запросы от внешних DNS-серверов):

sudo iptables -A FORWARD -p udp -d 10.160.0.253 --sport 53 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 10.160.0.253 --sport 53 -m state --state ESTABLISHED -j ACCEPT 

sudo iptables -A FORWARD -p udp -d 10.160.0.254 --sport 53 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 10.160.0.254 --sport 53 -m state --state ESTABLISHED -j ACCEPT

3. С помощью NAT выполняем маскировку любых пакетов идущих из локальной сети в Интернет (на WAN-интерфейс eth1) меняя в пакетах адрес источника на конкретный IP-адрес WAN-интерфейса:

sudo iptables -t nat -A POSTROUTING -o eth1 -s 10.0.0.0/8 -j SNAT --to-source 62.99.99.99

В п.3 мы используем более широкое правило, которое разрешает NAT для любого трафика идущего из локальной сети в Интернет, так как подразумевается, что на этапе обработки данного правила (цепочка POSTROUTING  из таблицы nat) предварительная проверка на пересылку трафика по более узким правилам уже выполнена ранее в цепочке FORWARD таблицы filter.
Порядок обработки пакетов в таблицах iptables изложен в следующей схеме:

image

 

***

Теперь нужно проверить результат. Запускаем на каждом из внутренних DNS-серверов командную строку и пытаемся разрешить имя (например ya.ru) на внешнем DNS-сервере (например 8.8.8.8)

nslookup ya.ru 8.8.8.8

Если созданные нами правила форвардинга трафика DNS работают корректно, то получим от удалённого DNS-сервера ответ:

Server:  google-public-dns-a.google.com
Address:  8.8.8.8

Non-authoritative answer:
Name:    ya.ru
Addresses:  2a02:6b8::3
          213.180.204.3
          213.180.193.3
          93.158.134.3

***

Другой простой пример проброса трафика. Предположим в локальной сети есть сервер, отвечающий за мониторинг доступности разного рода внешних хостов в Интернете. Чтобы разрешить для такого сервера проброс ICMP-трафика в Интернет, учитывая ранее изложенные настройки, достаточно добавить лишь два правила:

sudo iptables -A FORWARD -p icmp -s 10.20.10.10 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -p icmp -d 10.20.10.10 -m state --state ESTABLISHED -j ACCEPT

***

По завершению правок всех правил не забываем сохранять их с помощью службы iptables-persistent:

sudo service iptables-persistent save

***

Для того, чтобы оценить все созданные в ходе этой заметки настройки iptables в комплексе, выполним:

sudo iptables-save

Будет выведен отчет по всем правилам для всех таблиц iptables:

# Generated by iptables-save v1.4.21 on Wed Jul  9 15:15:53 2014
*filter
:INPUT DROP [2511:1497828]
:FORWARD DROP [51842:2783575]
:OUTPUT ACCEPT [4006524:2749344105]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 3128 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 123 -j ACCEPT
-A INPUT -i eth0 -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A FORWARD -s 10.160.0.253/32 -p udp -m udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
-A FORWARD -s 10.160.0.253/32 -p tcp -m tcp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
-A FORWARD -s 10.160.0.254/32 -p udp -m udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
-A FORWARD -s 10.160.0.254/32 -p tcp -m tcp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
-A FORWARD -d 10.160.0.253/32 -p udp -m udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -d 10.160.0.253/32 -p tcp -m tcp --sport 53 -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -d 10.160.0.254/32 -p udp -m udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -d 10.160.0.254/32 -p tcp -m tcp --sport 53 -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -s 10.20.10.10/32 -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
-A FORWARD -d 10.20.10.10/32 -p icmp -m state --state ESTABLISHED -j ACCEPT
COMMIT
# Completed on Wed Jul  9 15:15:53 2014
# Generated by iptables-save v1.4.21 on Wed Jul  9 15:15:53 2014
*nat
:PREROUTING ACCEPT [559972:59968564]
:INPUT ACCEPT [301654:15634943]
:OUTPUT ACCEPT [198120:11959405]
:POSTROUTING ACCEPT [198122:11959540]
-A POSTROUTING -s 10.0.0.0/8 -o eth1 -j SNAT --to-source 62.99.99.99
COMMIT
# Completed on Wed Jul  9 15:15:53 2014

Если для операций редактирования правил нужно узнать порядковый номер какого-то конкретного правила, то можно воспользоваться несколько иным форматом вывода правил, в котором явно видны номера правил, например для таблицы filter:

sudo iptables -t filter -L --line-numbers

***

Вдогонку ссылки на пару простых сжатых статей помогающих в начальном освоении iptables:

8Host.Blog — Как работает фаервол IPTables
8Host.Blog — Настройка фаервола с помощью IPTables на Ubuntu 14.04

Всего комментариев: 5 Комментировать

  1. я /

    sudo iptables -A INPUT -m state —state ESTABLISHED,RELATED -j ACCEPT E у меня не сработало, пришлось менять порядок параметров ESTABLISHED,RELATED на RELATED,ESTABLISHED

  2. я /

    и возможно вместо -m state —state лучше использовать -m conntrack —ctstate

  3. Tims /

    sudo iptables -A INPUT -p tcp —dport 123 -i eth0 -j ACCEPT

    NTP использует для своей работы протокол UDP а не tcp

    1. Алексей Максимов / Автор записи

      Да, косяк. Тест на внимательность :)

  4. Tims /

    За статью спасибо !
    Добавлю что для Samba нужно открыть порты :
    sudo iptables -A INPUT -p tcp —dport 445 -i eth1 -j ACCEPT — Samba
    sudo iptables -A INPUT -p tcp —dport 139 -i eth1 -j ACCEPT —Samba
    sudo iptables -A INPUT -p udp —dport 137 -i eth1 -j ACCEPT —Samba NetBIOS
    sudo iptables -A INPUT -p udp —dport 138 -i eth1 -j ACCEPT —Samba NetBIOS

Добавить комментарий