Как Discourse может обходить UFW? Я включил только порт 22, значит все остальные порты должны быть закрыты. Но форум всё равно работал. Как это возможно?
Это Droplet от DigitalOcean, но это не должно иметь значения. И это не установка в один клик, а официальный способ.
Это не чисто вопрос поддержки, но у нас здесь нет категории под названием Глупые базовые вопросы новичков
Вы пробовали открыть форум в режиме инкогнито или в другом браузере? Легко запутаться из-за кэшированной версии. Я сам так попался, и другой разработчик сказал мне, что тестовый сайт выглядит хорошо, хотя он вообще не работал.
Только 22/tcp (OpenSSH) ALLOW IN Anywhere, как и должно быть. Это именно то, что я всегда делаю: разрешаю OpenSSH и включаю UFW.
Я открываю порты только при необходимости, например, когда собираюсь установить Nginx. Но поскольку этот VPS использовался только для Discourse, я ничего больше не делал — совсем забыл про UFW.
Это не может быть так. Этот форум работал уже несколько недель.
Я обнаружил эту ситуацию, когда подключил Nginx/Varnish к этому VPS и мне нужно было открыть ещё один порт — и я понял, что открыт только порт 22.
Редактирование:
Как же я мог отправлять письма? Порт 587 тоже не был открыт
Я не совсем понимаю, говорите ли вы, что значение по умолчанию установлено на «отказывать» или нет. Причина, по которой я спрашиваю конкретно о строке «Default», заключается в том, что можно иметь значение по умолчанию «разрешать» и при этом установить разрешение для конкретного порта, хотя в такой конфигурации последнее ничего не меняет.
Если Discourse настраивал кто-то другой, возможно, этот человек изменил значение по умолчанию на «разрешать» вместо того, чтобы открыть порты HTTP/HTTPS?
Я предполагаю, что речь идёт о SMTP-сервере где-то ещё, и ваш сервер Discourse подключается к этому SMTP-серверу через порт 587. Исходящие соединения по умолчанию разрешены на всех портах, поэтому UFW не будет мешать отправке писем, если вы явно не измените политику для исходящего трафика.
Нет. Но разрешает ли allow (outgoing) любой исходящий трафик? Если да, то мы возвращаемся к тому, что «у нас здесь нет категории под названием Глупые базовые вопросы новичков», и я узнал что-то новое.
Редактирование:
Я всё ещё в недоумении — но как насчёт deny (incoming)?
Короткий ответ: Discourse не может обойти правила вашего фаервола, а задавать глупые вопросы об операционных системах лучше где-нибудь вроде Stack Exchange. (Пожалуйста, не считайте меня грубым. Ответы на такие вопросы именно там. Я использую Linux с самых первых версий, но всё ещё обращаюсь туда со своими глупыми вопросами. Они у меня всё ещё есть!)
Я знаю это место Соотношение сигнала к шуму там слишком низкое. Ну, это не совсем точная характеристика, но я имел в виду, что оттуда действительно сложно найти что-то полезное. Там просто слишком огромный объём информации.
Это действительно очень хороший вопрос, и меня удивляет, что никто ещё не задал его. Ответ сложен, но, к сожалению, предыдущие ответы по этой теме были пренебрежительными по тону и не давали ответа на вопрос.
Дело не в том, что Discourse обходит ufw, а в том, что docker обходит ufw, добавляя правила, благодаря которым открытые порты контейнеров Docker работают, несмотря на наличие ufw.
Что происходит?
Входящие пакеты, предназначенные для контейнера, попадают в таблицу FORWARD, а не в таблицу INPUT, как можно было бы ожидать.
До установки Docker
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ufw-before-logging-forward all -- any any anywhere anywhere
0 0 ufw-before-forward all -- any any anywhere anywhere
0 0 ufw-after-forward all -- any any anywhere anywhere
0 0 ufw-after-logging-forward all -- any any anywhere anywhere
0 0 ufw-reject-forward all -- any any anywhere anywhere
0 0 ufw-track-forward all -- any any anywhere anywhere
После установки Docker
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
8 416 DOCKER-USER all -- any any anywhere anywhere
8 416 DOCKER-ISOLATION-STAGE-1 all -- any any anywhere anywhere
0 0 ACCEPT all -- any docker0 anywhere anywhere ctstate RELATED,ESTABLISHED
4 256 DOCKER all -- any docker0 anywhere anywhere
4 160 ACCEPT all -- docker0 !docker0 anywhere anywhere
0 0 ACCEPT all -- docker0 docker0 anywhere anywhere
0 0 ufw-before-logging-forward all -- any any anywhere anywhere
0 0 ufw-before-forward all -- any any anywhere anywhere
0 0 ufw-after-forward all -- any any anywhere anywhere
0 0 ufw-after-logging-forward all -- any any anywhere anywhere
0 0 ufw-reject-forward all -- any any anywhere anywhere
0 0 ufw-track-forward all -- any any anywhere anywhere
Причина, по которой пакеты попадают в таблицу FORWARD, заключается в правилах, которые Docker добавляет в таблицу nat:
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
210 12734 DOCKER all -- any any anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 any anywhere anywhere
0 0 DNAT tcp -- !docker0 any anywhere anywhere tcp dpt:https to:172.17.0.2:443
107 6848 DNAT tcp -- !docker0 any anywhere anywhere tcp dpt:http to:172.17.0.2:80
nat/PREROUTING обрабатывается до принятия решения о том, отправлять ли пакеты через INPUT или FORWARD.
В конечном итоге проблема заключается в том, что в системе есть два сервиса, изменяющие правила фаервола. ufw ничего об этом не знает, поэтому может сообщать только о том, что настроил он.
Решение
Одним из решений является перенастройка фаервола так, чтобы трафик, предназначенный для Docker, также проходил через цепочки ufw:
Я использую следующую небольшую адаптацию их работы, внедрённую до включения ufw:
# украдено из https://github.com/chaifeng/ufw-docker - выглядит разумно
# добавление forward в ufw-user-input позволяет подключениям
# к перенаправленным портам, которые мы явно открыли
cat <<EOUFW >> /etc/ufw/after.rules
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-user-input - [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 -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j ufw-user-input
-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 tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -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 DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER
EOUFW
Эта тема решена, но она выявила одну небольшую проблему в моей настройке. Я объясню её, если кто-то когда-нибудь будет искать что-то подобное.
У меня был один VPS, где Nginx отвечает за SSL и другие задачи для всех моих сайтов (их много, и английский — один из самых странных языков ;)). Nginx отправляет запросы в Varnish. Для Discourse это бесполезный обратный прокси, но он выполняет некоторую фильтрацию. Varnish пересылает запросы на другой VPS, где работает Discourse, используя порт 83. Оба VPS слушают один и тот же порт, и доступ разрешён только с обоих IP-адресов. Я был полностью доволен — до сих пор.
Я проверил, что происходит при использовании порта 443: curl -I https://forum.example.tld:443. Всё работало отлично, потому что на стороне Discourse всё ещё действовал SSL-сертификат (я внес эти изменения несколько недель назад).
Ответ от @supermathie объясняет, почему это происходит и как исправить ситуацию. Конечно, насколько мне известно, это не создаёт никаких проблем с безопасностью, но это действительно раздражает
Думаю, этот вопрос редко задают, потому что нечасто кто-то устанавливает Discourse и хочет, чтобы он не работал. Поэтому, когда Docker заставляет его работать, даже если вы настроили фаервол так, чтобы он не работал, люди в основном не жалуются.
Это очень интересная проблема, но она кажется немного эзотерической, и дело не в Discourse, а в особенности работы Docker. Вопрос сводится к следующему: «Как мне настроить фаервол, чтобы Discourse не работал?» Я постараюсь запомнить эти правила перенаправления.
Если бы я знал ответ, я бы не был пренебрежительным! Спасибо, что спас ситуацию в этот раз!
Я вовсе не стремился быть пренебрежительным, а скорее пытался помочь с устранением неполадок, хотя, очевидно, действовал в неведении о том, что именно делает Docker. Вся эта информация очень полезна, спасибо за ответ!
Если автор оригинального сообщения или кто-то другой сможет это сделать, возможно, стоит изменить отмеченное решение.
Хотя это больше связано с Docker, я вижу здесь возможные гипотетические сценарии для Discourse. Например, у меня может быть офисный сервер, доступный из внешнего мира, но я хочу настроить UFW так, чтобы Discourse был доступен только изнутри офиса. Особенности работы Docker помешали бы такой настройке.
Хотя в данном конкретном случае я бы всё равно настроил это на уровне аппаратного брандмауэра или гипервизора, а не через UFW на хост-машине.
На самом деле, я через некоторое время разобрался и написал этот bash-скрипт для выполнения задачи при установке Discourse.
Он сбрасывает ваш брандмауэр, устанавливает ufw-docker-util (который редактирует after.rules), а затем добавляет порты 443 и 80 в ваш список разрешённых. Вот и всё.
Также скрипт разрешает порт 22 для любого IP-адреса, чтобы вы случайно не потеряли доступ. После завершения всех работ снова обеспечьте безопасность порта 22.
РЕДАКТИРОВАНИЕ: скрипт работает, но пересборка Discourse после его использования завершится ошибкой: fatal: unable to access 'https://github.com/discourse/discourse.git/': Could not resolve host: github.com. Поэтому НЕ используйте скрипт, если не знаете, как решить эту проблему.
РЕДАКТИРОВАНИЕ 2: Работает на Ubuntu, но не на CentOS!
В прошлый раз, когда я писал bash-скрипт, я изменил владельца всех директорий на www-data:www-data — для меня такая работа немного упрощает жизнь
Но в целом — я бы хотел, чтобы Docker полностью следовал правилам UFW/iptables. Просто потому что я использую блокировку по GeoIP через iptables (да, я знаю — UFW это лишь минималистичный интерфейс для iptables).
Конечно, мы уже не в Discourse, но здесь видно, почему разработчики и конечные пользователи не всегда хорошо понимают друг друга: разработчики видят мир как логические блоки и конструкции if/then/else, а конечные пользователи видят его в полном контексте. То есть — поскольку я использую Discourse, даже если он работает внутри Docker, с моей точки зрения именно Discourse не следует моим правилам
Это должно было попасть в #praise, но несколько недель назад я изменил URL форума. И ко мне пришли все скрипт-кидди и бесполезные SEO-боты со всего мира. На моём VPS от DigitalOcean с 2 ГБ ОЗУ и 1 vCPU приходило 3000 разных User-Agent в час, и Discourse просто не обращал на это внимания. Любая установка WordPress после такого DDOS-подобного наплыва стала бы медленной или упала бы.
Так что мне не так уж и нужно заставлять Discourse (ну, Docker) соблюдать блокировки Fail2ban и мои правила — но я глубоко ненавижу этих ботов.