Шпаргалка по iptables
Возможно, это не законченный вариант статьи. Шпаргалка будет обновляться, по мере того как я буду узнавать что-то новое или находить ошибки.
#Что это и для чего?
Iptables — утилита командной строки для управления брандмауэром netfilter ядра Linux >=2.4 .
В книге «Unix и Linux Руководство системного администратора» дается следующее описание iptables :
Утилита iptables применяет к сетевым пакетам упорядоченные цепочки правил. Наборы цепочек образуют таблицы и используются для обработки определенных видов трафика.
По умолчанию используется таблица filter . Цепочки правил в этой таблице используются для пакетной фильтрации сетевого трафика
Ручная настройка, особенно впервые, вызывает значительные затруднения, авторы указанной книги этого не отрицают.
#Терминология
iptables включает следующие таблицы:
- filter — фильтрация сетевого трафика
- nat — управление преобразованием сетевых адресов
- mangle — модификация и замена содержимого сетевых пакетов вне контекста NAT и фильтрации пакетов
Рассматривать мы будем именно filter , которая является таблицей по умолчанию для всех команд утилиты iptables , если иное не сказано явно.
Цепочка — это упорядоченный набор правил.
Цепочки бывают базовые/встроенные и пользовательские (можно создать самому).
К базовым цепочкам относятся:
- INPUT — входящий трафик (адресованный локальному хосту)
- FORWARD — транзитный трафик поступающий на локальную машину с целью передачи его на другую машину (трафик передаваемый в docker контейнер тоже будет считаться транзитным), при этом транзитный трафик проходит в обоих направлениях (с текущей машины на другую и с другой машины на текущую)
- OUTPUT — исходящий из локального хоста трафик
В новую цепочку можно направлять пакеты чтобы подвергуть их анализу правил. Например для отладки правил или настройки особого движения пакетов как это сделано в Docker .
Правило — состоит из условия/критерия (если нет значит применяется ко всему трафику) действия (может не быть) и счетчика (для учета пакетов попавших под правило).
- -p — протокол ( TCP , UDP , ICMP , ALL )
- -s — ip адрес источника (можно с маской 10.0.0.0/24 ), допускается отрицание (т.е. все кроме) -s ! 10.0.0.0/24
- -d — ip адрес получателя (аналогично -s )
- -i — интерфейс с которого пришел пакет (только для INPUT , FORWARD , PREROUTING ), например ens3 , допускается указать ens+ что означает все имена интерфейсов начинающиеся с заданной строки, допускается отрицание -i ! ens+
- -o — интерфейс локального хоста, из которого выходит трафик (только для OUTPUT , FORWARD , PREROUTING )
- —sport — порт с которого был отправлен TCP / UDP пакет (допускаются имена служб из /etc/services ), поддерживаются диапазоны вида 20:80 что значит от 20 до 80 порта, так же можно опустить одно из значений :80 (от 0 до 80) или 20: (от 20 до 65535), отрицание поддерживается даже к диапазонам —sport ! 20:80
- —dport — аналогично —sport только речь идет про порт, которому адресован пакет
- —icmp-type — тип ICMP сообщения (номер или название), поддерживается отрицание. RFC 792 или iptables —protocol icmp —help
- -m mac —mac-source — MAC адрес устройства передавшего пакет, поддерживается отрицание
- -m state —state — состояние соединения:
- INVALID — неизвестное соединение, возможно ошибочное
- NEW — новое соединение
- ESTABLISHED — уже установленное соединение
- RELATED — пакет принадлежит уже существующему соединению, но он отправляется по новому
- —ttl-eq N — TTL пакета равен N
- —ttl-lt N — TTL пакета меньше N
- —ttl-gt N — TTL пакета больше N
- ACCEPT — пакет принят в текущей таблице
- DROP — пакет сбрасывается и перестает движение в системе
- LOG — пакет журналируется и продолжает дальнейшие движение по цепочке правил и таблицам (рассмотрим ниже)
- REJECT — аналогично DROP только отдает сообщение об ошибке на хост отправителя (работает на всех цепочках таблицы filter ):
- —reject-with — тип ответа, RFC 793 или iptables -j REJECT -h
#Работа с iptables
Правила iptables действуют до перезагрузки системы, так что если было сделано что-то не так, можно перезагрузить машину и правила iptables будут сброшены.
#Просмотр
Справка вызывается стандартно:
А так можно просмотреть таблицу filter в табличном виде со статистикой и нумерацией правил:
$ sudo iptables -vnL --line-numbers
Это скриншот правил таблицы filter для vpn сервера, здесь видно что:
- для цепочки INPUT политика по умолчанию DROP , в итоге было отброшено 78606 пакетов (4536кб)
- для цепочки FORWARD политика по умолчанию тоже DROP , но пакетов подходящих под правила не было
- для цепочки OUTPUT политика по умолчанию ACCEPT и через эту цепочку прошло 347 млн. пакетов (59гб)
Также можно распечатать правила:
-P INPUT DROP -P FORWARD DROP -P OUTPUT ACCEPT -A INPUT -p udp -m udp --dport 1194 -j ACCEPT -A INPUT -i tun+ -j ACCEPT -A INPUT -p udp -m udp --dport 53 -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i tun+ -j ACCEPT -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
#Управление правилами и цепочками
Добавить правило (разрешить весь трафик с tun интерфейсов) в конец цепочки INPUT ( -A , —append ):
$ sudo iptables -A INPUT -i tun+ -j ACCEPT
Вставить правило в позицию 2 цепочки INPUT ( -I , —insert ):
$ sudo iptables -I INPUT 2 -i lo -j ACCEPT
Установить политику по умолчанию DROP для цепочки INPUT ( -P , —policy ):
$ sudo iptables -P INPUT DROP
Создание новой цепочки правил:
#Примеры
Предположим что для цепочки INPUT политика по умолчанию DROP , это значит что все входящие пакеты будут отброшены, но нам нужен некоторый входящий трафик.
Разрешим трафик на локальный DNS сервер, без этого могут быть долгие подключения по ssh :
$ sudo iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
Разрешим движение трафика из интерфейсов создаваемых Docker (при политиках по умолчанию DROP , контейнеры не смогут общаться с другими интерфейсами):
$ sudo iptables -A INPUT -i br+ -j ACCEPT
Разрешим любой входящий трафик из localhost и откроем http / https порты ( 80 / 443 ), например для случая когда у нас есть веб-сервер и наши сайты должны быть доступны снаружи:
$ sudo iptables -A INPUT -i lo -j ACCEPT $ sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT $ sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
Если не разрешить входящий трафик от localhost то могу быть странные задержки с ответами, а при дебаге можно увидеть отклоенные пакеты от 127.0.0.1
Теперь локальный DNS на 53 порту доступен, docker контейнеры тоже, с localhost трафик разрешен, и для внешнего мира открыты 80 и 443 порты для наших сайтов. Но это все только для установления соединения и рукопожатия. Теперь нам нужно разрешить все установленные и связанные с ними соединения чтобы трафик действительно пошел (еще вот):
$ sudo iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
#Сброс всех правил таблицы filter
# удаление всех цепочек $ sudo iptables -F # разрешение всего входящего трафика $ sudo iptables -P INPUT ACCEPT # разрешение перенаправление трафика $ sudo iptables -P FORWARD ACCEPT # разрешение всего исходящего трафика $ sudo iptables -P OUTPUT ACCEPT
#Отладка
#Логирование отклоненных пакетов
Полезно иметь возможно отладить свои правила, экономия времени и iptables становится понятнее.
Суть отладки правил iptables такова:
- создаем отдельную цепочку, куда будем перенаправлять весь трафик, который должен быть отклонен
- в новой цепочке ведем логирование и отклоняем пакеты
- направляем запросы для теста правил и смотрим лог отклоенных пакетов
Добавляем правило логирования каждого пакета с префиксом:
$ sudo iptables -A LOGGING -j LOG --log-prefix "ipt denied: "
$ sudo iptables -A LOGGING -j DROP
В цепочку, откуда будут приходить пакеты для отклонения добавляем новое правило перенаправления в новую цепочку логирования:
$ sudo iptables -A INPUT -j LOGGING
Теперь добавим конфиг rsyslog :
$ sudo nano /etc/rsyslog.d/10-iptables.conf
:msg, contains, "ipt denied: " -/var/log/iptables.log & ~
Сохраним и перезагрузим демона rsyslog :
$ sudo service rsyslog restart
Теперь откроем файл и будем следить за 20 последних строк:
$ sudo echo > /var/log/iptables.log $ sudo tail -f -n 20 /var/log/iptables.log
Можно наблюдать что-то такое:
Feb 19 17:43:36 logic kernel: [14331.939805] ipt denied: IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 DF PROTO=TCP SPT=49104 DPT=6000 WINDOW=65495 RES=0x00 SYN URGP=0 Feb 19 17:43:44 logic kernel: [14340.132036] ipt denied: IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 DF PROTO=TCP SPT=49104 DPT=6000 WINDOW=65495 RES=0x00 SYN URGP=0 Feb 19 17:43:46 logic kernel: [14342.030775] ipt denied: IN=ens3 OUT= MAC=52:54:00:10:23:3f:4c:96:14:68:fb:f0:08:00 SRC=78.155.213.173 DST=185.105.90.67 LEN=40 TOS=0x00 PREC=0x00 TTL=250 PROTO=TCP SPT=57587 DPT=54402 WINDOW=1024 RES=0x00 SYN URGP=0 Feb 19 17:43:52 logic kernel: [14348.160719] ipt denied: IN=ens3 OUT= MAC=52:54:00:10:23:3f:4c:96:14:68:fb:f0:08:00 SRC=89.248.165.209 DST=185.105.90.67 LEN=40 TOS=0x00 PREC=0x00 TTL=248 PROTO=TCP SPT=49784 DPT=23988 WINDOW=1024 RES=0x00 SYN URGP=0
#Сохранение
При перезагрузке системы правила iptables будут сброшены.
Чтобы происходило восстановление сохраненных правил нужен пакет iptables-persistent :
$ sudo apt install iptables-persistent
Необходимо проверить работает ли демон systemd :
$ sudo systemctl status netfilter-persistent
Если нет, его нужно запустить:
$ sudo systemctl start netfilter-persistent
После настройки и отладки правил iptables нужно сохранить их в файл /etc/iptables/rules.v4 чтобы при старте системы демон netfilter-persistent загрузил их в iptables .
Сохранение правил iptables в файл:
$ sudo iptables-save > /etc/iptables/rules.v4
Теперь правила должны загружаться после перезагрузки системы.
Для ручной загрузки правил правил из файла в iptables можно сделать так:
#Литература
Эта шпаргалка не получилась бы без сторонних источников откуда я черпал информацию для изучения. Здесь я узнал про сохранение правил iptables , а в этом руководстве почерпнул много теории (и здесь). На некоторые вопросы дал ответы этот топик, а про локальный dns узнал здесь. Отладку взял отсюда, а доделать правила для vpn помог этот топик.
В телеграм канале DevOps от первого лица можно оставить комментарий или почитать интересные истории из практики DevOps