Какова лучшая практика docker + ufw под Ubuntu
Я только что попробовал Докера. Это потрясающе, но, кажется, не очень хорошо работает с ufw. По умолчанию docker будет немного манипулировать iptables. Результат не ошибка, но и не то, что я ожидал.
Для получения более подробной информации вы можете прочитать опасности UFW + Docker
Моя цель-создать систему, подобную
Host (running ufw) -> docker container 1 - nginx (as a reverse proxy)
-> docker container 2 - node web 1
-> docker container 3 - node web 2
-> .......
Я хочу управлять входящим трафиком (например, ограничить доступ) через ufw, поэтому я не хочу, чтобы docker прикасался к моим iptables. Вот мой тест
Окружающая среда:
- недавно установленная Ubuntu 14.04 (ядро: 3.13.0-53)
- Докер 1.6.2
- включена переадресация ufw.(включить переадресацию UFW )
--iptables=falseбыл добавлен в демон Docker.
Первая Попытка
docker run --name ghost -v /home/xxxx/ghost_content:/var/lib/ghost -d ghost
docker run --name nginx -p 80:80 -v /home/xxxx/nginx_site_enable:/etc/nginx/conf.d:ro --link ghost:ghost -d nginx
Не повезло. Первая команда хороша, но вторая команда выдаст ошибку
Error response from daemon: Cannot start container
Вторая Попытка
Затем я обнаружил следующее: неспособен чтобы связать контейнеры с --iptables=false #12701
После выполнения следующей команды все выглядит нормально.
sudo iptables -N DOCKER
Однако я заметил, что не могу установить исходящие соединения внутри контейнеров. Например:
xxxxg@ubuntu:~$ sudo docker exec -t -i nginx /bin/bash
root@b0d33f22d3f4:/# ping 74.125.21.147
PING 74.125.21.147 (74.125.21.147): 56 data bytes
^C--- 74.125.21.147 ping statistics ---
35 packets transmitted, 0 packets received, 100% packet loss
root@b0d33f22d3f4:/#
Если я удалю --iptables=false из демона Docker, то подключение контейнеров к интернету вернется в нормальное состояние, но ufw не будет работать "должным образом" (well...by мое определение).
Итак, какова лучшая практика docker + ufw? Мочь кто-нибудь может помочь?
Спасибо.
Барт
4 ответов:
У меня была такая проблема несколько месяцев назад, и недавно я решил описать эту проблему вместе с решением в своем блоге. Вот кратчайший путь.
Использование
Есть небольшой шаг, который вы пропускаете на своем пути, чтобы иметь контейнеры позади UFW здесь. Вы можете использовать--iptables=falseне очень поможет вам в описанном случае. Здесь этого просто недостаточно. По умолчанию ни один из ваших контейнеров не может выполнять исходящее соединение.--iptables=falseили создать/etc/docker/daemon.jsonфайл с содержимым следующим образом{ "iptables": false }В результат будет тот же, но последний вариант требует перезапуска всей службы docker с помощью
service docker restartили даже перезагрузки, если docker имел возможность добавить правила iptables до того, как вы отключили эту функцию.Когда это будет сделано, просто сделайте еще две вещи:
$ sed -i -e 's/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/g' /etc/default/ufw $ ufw reloadТаким образом, вы устанавливаете политику переадресации по умолчанию в UFW для accept и используете:
$ iptables -t nat -A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADEТаким образом, вы добиваетесь того, что отключаете Docker грязное поведение в ваших правилах iptables, и в то же время docker снабжен необходимая маршрутизация, так что контейнеры будут делать исходящие соединения просто отлично. Однако с этого момента правила UFW будут по-прежнему ограничены.
Надеюсь, что это решит проблему для вас и всех, кто приходит сюда в поисках ответа.
Я более подробно описал проблему и ее решение в https://www.mkubaczyk.com/2017/09/05/force-docker-not-bypass-ufw-rules-ubuntu-16-04/
Проблема
Эта проблема была вокруг в течение долгого времени.
Отключение iptables в Docker приведет к другим проблемам.
Откат меняется первым
Если вы изменили свой сервер в соответствии с текущим решением, которое мы находим в интернете, пожалуйста, сначала откатите эти изменения, включая:
- включите функцию iptables Docker. Удалите все изменения, такие как
--iptables=false, включая файл конфигурации/etc/docker/daemon.json.- прямое правило UFW по умолчанию возвращается к значению по умолчанию
DROPвместоACCEPT.- удалить правила, относящиеся к сети настройки в файле конфигурации сооружения
/etc/ufw/after.rules.- если вы изменили файлы конфигурации Docker, сначала перезапустите Docker. Мы изменим конфигурацию UFW позже,и тогда мы сможем перезапустить его.
Решение проблем UFW и Docker
Это решение должно изменить только один файл конфигурации UFW, все конфигурации и параметры Docker остаются по умолчанию. Не необходимо отключить функцию docker iptables.
Измените файл конфигурации UFW
/etc/ufw/after.rulesи добавьте в конец файла следующие правила:# BEGIN UFW AND DOCKER *filter :ufw-user-forward - [0:0] :DOCKER-USER - [0:0] -A DOCKER-USER -j RETURN -s 10.0.0.0/8 -A DOCKER-USER -j RETURN -s 172.16.0.0/12 -A DOCKER-USER -j RETURN -s 192.168.0.0/16 -A DOCKER-USER -j ufw-user-forward -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 -A DOCKER-USER -j RETURN COMMIT # END UFW AND DOCKERС помощью команды
sudo systemctl restart ufwперезапустить UFW после изменения файла. Теперь публичная сеть не может получить доступ к каким-либо опубликованным портам docker, контейнер и частная сеть могут регулярно посещать друг друга, а контейнеры могут также получать доступ к внешней сети изнутри.Если вы хотите разрешить публичным сетям доступ к услугам, предоставляемым контейнером Docker, например, порт обслуживания контейнера
80. Выполните следующую команду, чтобы разрешить сетям общего пользования доступ к этой службе:ufw route allow proto tcp from any to any port 80Эта команда позволяет публичной сети получить доступ ко всем опубликованным портам, контейнерный порт которых равен 80.
Примечание: если мы публикуем порт с помощью опции-p 8080:80, мы должны использовать контейнерный порт80, а не Порт хоста8080.Если имеется несколько контейнеров со службой порт 80, но мы хотим, чтобы внешняя сеть имела доступ только к определенному контейнеру. Например, если частный адрес контейнера равен 172.17.0.2, используйте следующую команду:
ufw route allow proto tcp from any to 172.17.0.2 port 80Если сетевой протокол службы является UDP, например, службой DNS, можно использовать следующую команду, чтобы разрешить внешней сети доступ ко всем опубликованным службам DNS:
ufw route allow proto udp from any to any port 53Аналогично, если только для конкретного контейнера, такого как IP-адрес 172.17.0.2:
ufw route allow proto udp from any to 172.17.0.2 port 53Как это работает?
Следующие правила позволяют частным сетям иметь возможность посещать друг друга. Как правило, частные сети более надежны, чем публичные.-A DOCKER-USER -j RETURN -s 10.0.0.0/8 -A DOCKER-USER -j RETURN -s 172.16.0.0/12 -A DOCKER-USER -j RETURN -s 192.168.0.0/16Следующие правила позволяют UFW управлять тем, разрешено ли сетям общего пользования посещать службы, предоставляемые контейнером Docker. Так что мы можем управлять всеми правилами брандмауэра в одном месте.
-A DOCKER-USER -j ufw-user-forwardСледующие правила блокируют запросы на подключение, инициируемые всеми общедоступными сетями, но разрешают внутренние сети для доступа к внешним сетям. Для протокола TCP он препятствует активному установлению TCP-соединения из общедоступных сетей. Для протокола UDP все доступы к портам, которые меньше 32767, блокируются. Почему это портвейн? Поскольку протокол UDP не имеет состояния, невозможно заблокировать сигнал рукопожатия, который инициирует запрос на соединение, как это делает TCP. Для GNU/Linux мы можем найти диапазон локальных портов в файле
/proc/sys/net/ipv4/ip_local_port_range. Диапазон по умолчанию -32768 60999. При обращении к протоколу UDP служба из запущенного контейнера, локальный порт будет случайным образом выбран один из диапазона портов, и сервер вернет данные в этот случайный порт. Поэтому мы можем предположить, что порт прослушивания протокола UDP внутри всех контейнеров меньше 32768. Это является причиной того, что мы не хотим, чтобы публичные сети имели доступ к портам UDP, которые меньше, чем 32768.-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 -A DOCKER-USER -j RETURNЕще
Https://github.com/chaifeng/ufw-docker
sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker chmod +x /usr/local/bin/ufw-dockerИспользование
ufw-docker help ufw-docker install ufw-docker status ufw-docker allow webapp ufw-docker allow webapp 80 ufw-docker allow webapp 53/udp ufw-docker list webapp ufw-docker delete allow webapp 80/tcp ufw-docker delete allow webapp
Обновление: 2018-09-10
Причина выбора
ufw-user-forward, а неufw-user-inputИспользуя
ufw-user-inputPro:
Проста в использовании и понимании, поддерживает более старые версии Ubuntu.
Например, чтобы разрешить публике посещать опубликованный порт, контейнерным портом которого является
8080, используйте команда:ufw allow 8080Кон:
Он не только открывает порты контейнеров, но и открывает порты хоста.
Например, если служба запущена на хосте, а порт
8080. Командаufw allow 8080позволяет публичной сети посетить сервис и все опубликованные порты, порт контейнеров которых8080. Но мы просто хотим представить службу, работающую на хосте, или просто службу, работающую внутри контейнеров, а не то и другое.Чтобы избежать этой проблемы, мы можем необходимо использовать команду, аналогичную следующей для всех контейнеров:
ufw allow proto tcp from any to 172.16.0.3 port 8080Используя
ufw-user-forwardPro:
Не может предоставлять службы, работающие на хостах и контейнерах одновременно с помощью одной и той же команды.
Например, если мы хотим опубликовать порт
8080контейнеров, используйте следующую команду:Публичная сеть может получить доступ ко всем опубликованным портам, контейнерными портами которых являютсяufw route allow 80808080.Но порт
8080хоста все еще не является доступ осуществляется по общедоступной сети. Если мы хотим сделать это, выполните следующую команду, чтобы разрешить публичный доступ к порту на хосте отдельно:ufw allow 8080Кон:
Не поддерживает старые версии Ubuntu, и команда немного сложнее. Но вы можете использовать мой сценарий https://github.com/chaifeng/ufw-docker .
Заключение
Если мы используем более старую версию Ubuntu, мы можем использовать цепочку
Если мы используем более новую версию Ubuntu, которая поддерживает субкомандуufw-user-input. Но будьте осторожны, чтобы избежать разоблачения услуг, которые не следует подвергаться воздействию.ufw route, нам лучше использовать цепочкуufw-user-forwardи использовать командуufw routeдля управления правилами брандмауэра для контейнеров.
Обновление: 6 Октября 2018
Скрипт ufw-docker теперь поддерживает Docker Swarm. Пожалуйста, смотрите последний код для получения дополнительной информации, https://github.com/chaifeng/ufw-docker
Установка для режима Docker SwarmМы можем использовать этот скрипт только в менеджере узлы для управления правилами брандмауэра при использовании в режиме Роя.
- изменение всех
after.rulesфайлов на всех узлах, включая менеджеров и работников- развертывание этого скрипта на узлах диспетчера
Запущенный в режиме Docker Swarm, этот скрипт добавит глобальную службу
ufw-docker-agent. Образchaifeng/ufw-docker-agent также автоматически создается из этого проекта.
Для чего это стоит, вот дополнение к ответу @mkubaczyk для случая, когда во всей установке задействовано больше мостовых сетей. Они могут быть предоставлены проектами Docker-Compose, и вот как могут быть сгенерированы соответствующие правила, учитывая, что эти проекты управляются
systemd.
/etc/systemd/system/[email protected][Unit] Description=Docker-Compose project: %I After=docker.service BindsTo=docker.service AssertPathIsDirectory=/<projects_path>/%I AssertFileNotEmpty=/<projects_path>/%I/docker-compose.yml [Service] Type=simple Restart=always WorkingDirectory=/<projects_path>/%I ExecStartPre=/usr/bin/docker-compose up --no-start --remove-orphans ExecStartPre=+/usr/local/bin/update-iptables-for-docker-bridges ExecStart=/usr/bin/docker-compose up ExecStop=/usr/bin/docker-compose stop --timeout 30 TimeoutStopSec=30 User=<…> StandardOutput=null [Install] WantedBy=multi-user.target
/usr/local/bin/update-iptables-for-docker-bridgesОчевидно, что это не будет масштабироваться так хорошо.#!/bin/sh for network in $(docker network ls --filter 'driver=bridge' --quiet); do iface=$(docker network inspect --format '{{index .Options "com.docker.network.bridge.name"}}' ${network}) [ -z $iface ] && iface="br-${network}" subnet=$(docker network inspect --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' ${network}) rule="! --out-interface ${iface} --source ${subnet} --jump MASQUERADE" iptables --table nat --check POSTROUTING ${rule} || iptables --table nat --append POSTROUTING ${rule} doneТакже примечательно, что вся основная концепция будет маскировать источник любого подключение для приложений, работающих в контейнере.
Не совсем уверен, что вы спрашиваете, но из того, что я могу собрать, Вы хотели бы лучше контролировать, кто может получить доступ к вашим приложениям, запущенным внутри Docker? Я ответил на аналогичный вопрос здесь, чтобы управлять трафиком через прокси-сервер переднего плана, а не с помощью таблиц IP блокировать внешний доступ к контейнерам docker
Надеюсь, это поможет
Дилан
Edit
При вышеуказанном подходе вы можете использовать UFW только для разрешения входящих подключений к порту 80 (т. е. прокси). Это держит любое воздействие порта к минимуму с дополнительным бонусом, что вы можете контролировать трафик через конфигурацию прокси & DNS
Comments