Хост iptables только через VPN: назовите устройство tun, а не tun+
tun+ соответствует каждому туннелю на машине. Закрепите одно имя устройства, поставьте исключение для endpoint первым и сохраняйте путь восстановления, пока проверяете политику.
Написать -o tun+ кажется точной инструкцией, а на деле это шаблон, который совпадает с каждым туннелем в ядре. Второй клиент VPN, мост контейнеров или интерфейс, оставшийся от рухнувшей сессии, — все они удовлетворяют ему, и хост начинает пропускать трафик, который политика должна была не пустить. Процедура ниже закрепляет одно имя устройства, выстраивает исключения так, чтобы туннель действительно мог подняться, и оставляет путь назад, если правила лягут неудачно. Каждый шаг достаточно короток, чтобы отменить его отдельно.
Шаг 1: запишите правила, которые есть сейчас
Прежде чем менять политику по умолчанию, сохраните текущее состояние, чтобы откат был командой, а не воспоминанием. iptables-save > /root/iptables.pre записывает каждую таблицу в файл, который можно восстановить, а второй терминал с открытой root-сессией — не паранойя, когда задаваемая политика рвёт соединение, которое её несёт. Если вы работаете удалённо, запланируйте ещё и flush как аварийный выключатель.
Затем перечислите интерфейсы, потому что имя, которое вы предположили, — это имя, которое следовало прочитать: ip -br link показывает, что есть прямо сейчас, а туннель появится только после подъёма. Записывайте имена устройств по мере чтения.
Шаг 2: дайте туннелю собственное имя
OpenVPN принимает dev tun_work в конфигурации клиента, и тогда Linux создаёт интерфейс ровно с этим именем вместо того, чтобы выделять tun0. Имя остаётся стабильным между переподключениями, пока ничто другое на него не претендует, и именно это делает правило, называющее устройство, осмысленным.
Там, где именем нельзя управлять, сопоставляйте вместо этого адрес туннеля или метку пакета. Оба варианта работают, оба труднее читать, и оба тише отказывают, когда туннель перенумеровывается. В любом случае сопоставляйте одну вещь и прямо скажите, какую.
Шаг 3: напишите политику, поставив исключение для endpoint первым
Хост только через VPN — это хост с запретом по умолчанию и коротким списком исключений, и важнее всего исключение, которое позволяет туннелю существовать. Стройте его в этом порядке, с правилом для endpoint перед правилом для устройства туннеля, чтобы рукопожатию было куда идти:
# allow the tunnel to be built, then everything the tunnel carries
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -d 198.51.100.7 -p udp --dport 1194 -j ACCEPT
iptables -A OUTPUT -o tun_work -j ACCEPT
iptables -A INPUT -i tun_work -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTБуквальный адрес endpoint и порт принадлежат вашему провайдеру, а не этой странице. Если endpoint — имя хоста, разрешите его один раз и закрепите результат, потому что правило не умеет искать имя, а меняющийся ответ молча сломает политику после следующего изменения DNS. Проверьте и порт, потому что провайдеры, переводящие вас на TCP 443, иначе потребуют правила, которого никто не записал. Туннель, работающий только по одному протоколу, обычно и есть этот пропуск, а не неисправность межсетевого экрана.
На маршрутизаторе та же форма идёт в цепочку FORWARD для клиентов за ним, а собственному трафику маршрутизатора нужны свои правила. Набор правил, покрывающий только пересылаемые пакеты, оставляет SSH и DNS на старом пути, и именно так маршрутизатор становится недоступным в момент, когда туннель поднимается.
Шаг 4: проверьте порядок, а не только наличие
Правила оцениваются по порядку, поэтому ACCEPT, стоящий раньше, просто скрывает REJECT, добавленный после. Сопоставление established и related позволяет ответам на ваши собственные исходящие запросы возвращаться, не открывая общий входящий путь, а размещение его после принятия туннеля означает, что упавший туннель всё ещё пропускает обратный трафик на своём интерфейсе.
Держите число правил достаточно малым, чтобы прочитать их на одном экране. Набор правил, который вы не можете проверить аудитом, — это тот, который вы будете латать, добавляя исключения сверху, и именно так политики запрета по умолчанию постепенно приобретают край разрешения по умолчанию. Сосчитайте ACCEPT до и после изменения.
Шаг 5: сделайте так, чтобы он пережил загрузку и семейство адресов
Правила, введённые вручную, исчезают при перезагрузке, поэтому загружайте их из службы межсетевого экрана дистрибутива или из unit, который запускается после появления интерфейса туннеля. Ссылка на tun_work в скрипте, который выполняется до старта OpenVPN, — распространённый способ получить цикл загрузки со сброшенным трафиком.
Затем проверьте IPv6 отдельно, потому что хорошая политика запрета по умолчанию для IPv4 ничего не говорит о другом семействе. ip -6 route покажет, есть ли у хоста маршрут, который мог бы нести трафик в обход туннеля, обрабатывающего только IPv4, а ip6tables или nftables требуют собственных эквивалентных правил. Тестируйте с назначением IPv6-only, а не полагайтесь на симметрию набора правил.
Шаг 6: проверьте и будьте готовы восстановить
Поднимите туннель, убедитесь, что нужная служба работает, затем попробуйте то, что политика должна отклонить. Восстановите с помощью iptables-restore < /root/iptables.pre, если ответ вас удивит, и только после этого начинайте править правила. Устойчивость плюс проверенный путь восстановления — это то, что делает изменение таким, которое можно выполнить дважды.