Ко мне иногда обращаются разработчики с просьбами заблокировать доступ к какому-нибудь контейнеру из интернета. Для тех, кто не знает, скажу, что Docker по-умолчанию поднимает свои контейнеры с доступом к ним отовсюду. Никаких ограничений нет и настроить их не очень просто без понимания работы docker и iptables.
На углубленном курсе "Архитектура современных компьютерных сетей" вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.
Docker облегчил работу современным разработчикам и усложнил жизнь админам. Если не умеете с ним работать, смотрите мою статью по установке docker на centos. Такая простая задача, как блокировка доступа к какому-то сервису с помощью iptables резко усложнилась. Например, есть у вас одиночный сервер, на нем работают несколько контейнеров docker. Iptables вы не настраивали вообще, своих правил нет.
Тем не менее, набор правил iptables на хосте будет примерно такой.
Docker создает бриджи, свои цепочки, правила и т.д. Причем управляет всем этим динамически. Нельзя просто взять и настроить iptables, как это делаю я в своей статье с помощью скрипта. Такой подход уже не работает.
В крупных проектах эта проблема решается просто - все хосты с контейнерами закрыты внешним шлюзом с фаерволом, который может из себя представлять все, что угодно, но не хост с контейнерами. Реализации могут быть любыми. Важно, что это отдельная сущность.
Тем, у кого контейнеры работают на отдельных хостах, смотрящих напрямую в интернет, надо что-то делать у себя. Я покажу простой пример, как заблокировать доступ к какому-то контейнеру Docker из интернет.
Докер создает отдельную цепочку DOCKER-USER. Она проверяется раньше основной динамической цепочки DOCKER. Если вы хотите настроить свои правила доступа к контейнерам, добавляйте их в цепочку DOCKER-USER. Сервис не будет их трогать и изменять при рестарте или изменениях в контейнерах. Подробнее об этом читайте в документации.
Допустим, у нас есть контейнер с postgresql, который забинден на порт хоста 5432. По-умолчанию, к нему будет доступ из интернета. Чтобы запретить доступ к контейнеру, необходимо применить следующее правило.
/sbin/iptables -I DOCKER-USER -i eth0 -p tcp --dport 5432 -j DROP
В данном примере eth0 - внешний интерфейс, который смотрит в интернет. Усложним задачу. Вам надо запретить доступ из интернета к контейнеру, но при этом разрешить доступ с определенных ip адресов. Нам нужно применить несколько правил и следить за тем, чтобы разрешающие правила были выше запрещающих. Это можно сделать обычной нумерацией правил.
/sbin/iptables -I DOCKER-USER 1 -i eth0 -p tcp --dport 5432 -s 1.2.3.4 -j ACCEPT /sbin/iptables -I DOCKER-USER 2 -i eth0 -p tcp --dport 5432 -s 5.6.7.8 -j ACCEPT /sbin/iptables -I DOCKER-USER 3 -i eth0 -p tcp --dport 5432 -j DROP
Мы разрешили доступ с ip 1.2.3.4 и 5.6.7.8, всем остальным запретили, причем разрешающие правила поставили выше.
Посмотреть список правил конкретной цепочки с нумерацией можно командой:
# iptables -L DOCKER-USER --line-numbers -v -n
Если вам надо очистить конкретную цепочку с правилами, используйте команду.
/sbin/iptables -F DOCKER-USER
Если захотите заодно заблокировать посторонним людям доступ по ssh, добавьте следующие правила в цепочку INPUT.
/sbin/iptables -I INPUT 1 -p all -m state --state ESTABLISHED,RELATED -j ACCEPT /sbin/iptables -I INPUT 2 -i eth0 -p tcp --dport 22 -s 1.2.3.4 -j ACCEPT /sbin/iptables -I INPUT 3 -i eth0 -p tcp --dport 22 -s 5.6.7.8 -j ACCEPT /sbin/iptables -I INPUT 4 -i eth0 -p tcp --dport 22 -j DROP
Я рекомендую не лениться и закрывать доступ посторонним ко всему, что им не нужно. Важно делать это в том числе на dev серверах. Эта статья в основном для них. Разработчики часто создают тестовые серверы и особо не следят за ними, хотя там могут быть продуктовые базы и прочая приватная информация. Iptables для них темный лес.
Лучше сразу после создания dev сервера закрыть от посторонних глаз все, что на нем есть, используя простые правила, которые можно применить прямо в консоли.
Я предложил простое и топорное решение в лоб. Данную задачу можно решить различными способами. Например, правила iptables можно настраивать сразу вместе с контейнером и применять их при запуске. Можно вообще отключить динамическое управление правилами со стороны docker и писать их все самостоятельно. Но это все требует больше времени на настройку.
Чтобы после ребута сервера правила автоматически применились, можно оформить их в простой bash скрипт и запускать его с помощью cron, используя в качестве расписания параметр @reboot. Нужно только учесть один момент. Cron будет запускать скрипт раньше, чем успеет стартануть докер и создать свои цепочки. Надо каким-то образом его подождать. Самый простой способ поставить sleep на 5-10 секунд в скрипте перед применением правил для DOCKER-USER.
На углубленном курсе "Архитектура современных компьютерных сетей" вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.
Привет
Спасибо за статью.
У меня есть выделенная машина на hetzner
Я хочу разместить пару тройку контейнеров с базами данных + Airflow.
Я бы хотел, чтобы доступ к этим ресурсам был возможен только через VPN Wiregurd (запущен будет тоже в контейнере на том же хосте) и , так как часть "сервисов" не имеют защиты а только basic авторизация что недостаточно
Подскажите куда смотреть
Что вы подразумеваете под "выделенная машина на hetzner"? Это железный сервер?
Боюсь ошибиться в формулировках, в облаке ты арендуешь "машину" с голым линуксом ставишь все что хочешь
hetzner.com cloud
Это виртуальная машина. Тут вариант у вас один - разбираться с локальной настройкой фаервола - iptables. Сразу могу сказать, что это будет непростая задача, если в этом не разбираетесь.
Спасибо за статью!
Подскажите как заблокировать доступ к портам докера из интернета, но при этом разрешить доступ локальным программам, установленным на машине, например nginx?
По умолчанию у них будет доступ. В примерах из статьи я явно указываю в правилах, с каких интерфейсов запросы будут блокироваться:
Тут будут блокироваться запросы через интерфейс eth0, в моем случае это внешний интерфейс. Локальные запросы будут проходить.