UFW irá limitar o Discourse também?

Como o Discourse pode contornar o UFW? Eu ativei apenas a porta 22, então todas as outras portas deveriam estar fechadas. Mas um fórum funcionou de qualquer maneira. Como isso é possível?

Droplet DigitalOcean, mas isso não deveria significar nada. E nenhuma instalação com um clique, mas pelo caminho oficial.

Esta não é uma pergunta de suporte pura, mas não temos aqui uma categoria chamada Perguntas básicas estúpidas de iniciantes :wink:

7 curtidas

Então, se você ufw status verbose, você só vê o sshd?

1 curtida

Correto. E o UFW estava ativado.

1 curtida

O que foi listado como padrão quando você executou ufw status verbose?

Para o que eu acho que você quer, eu esperaria ver isto:
Padrão: negar (entrada), permitir (saída), desabilitado (roteado)

Com o comportamento que você está descrevendo, eu esperaria ver isto:
Padrão: permitir (entrada), permitir (saída), desabilitado (roteado)

1 curtida

Você tentou abrir o fórum em uma janela anônima ou em um navegador diferente? É fácil ser enganado pela versão em cache que aparece. Eu mesmo já fui enganado e outro desenvolvedor me disse que o site de testes estava bom quando, na verdade, ele não estava rodando.

1 curtida

Apenas 22/tcp (OpenSSH) ALLOW IN Anywhere como deveria ser. Essas são as duas coisas que sempre faço: permitir OpenSSH e habilitar UFW.

Eu abro portas apenas se necessário, como quando instalo o Nginx. Mas como aquele VPS era apenas para o Discourse, não fiz mais nada — esqueci totalmente do UFW.

Esse não pode ser o caso. Aquele fórum estava ativo há semanas.

Acordei com essa situação quando conectei Nginx/Varnish a esse VPS e precisei que outra porta fosse aberta — e percebi que a única porta aberta era a 22.

Editar:
Como eu poderia enviar e-mails? A porta 587 também não estava aberta :flushed_face:

Isso é realmente estranho.

1 curtida

Não está claro se você está dizendo que o padrão está definido como negar ou não. O motivo pelo qual pergunto especificamente sobre a linha “Default” é porque é possível ter um padrão de permitir e definir uma porta específica para permitir, embora esta última não mude nada nesse arranjo.

Se outra pessoa configurou o Discourse, é possível que essa pessoa tenha alterado o padrão para permitir em vez de permitir as portas HTTP/HTTPS?

Estou assumindo que isso é SMTP em outro lugar, seu servidor Discourse se conectando a esse servidor SMTP usando a porta 587. Conexões de saída são permitidas em todas as portas por padrão, então o UFW não atrapalhará o envio de e-mails, a menos que você altere explicitamente a política de saída.

4 curtidas

Minha falha :man_facepalming:

Default: deny (incoming), allow (outgoing), deny (routed)

Não. Mas allow (outgoing) permite alguma coisa de saída? Se sim, então voltamos a ter “não temos aqui uma categoria chamada Perguntas idiotas básicas de iniciantes” e eu aprendi coisas novas.

Editar:

Ainda estou perdido — mas como funciona deny (incoming)?

2 curtidas

Encontrei isto:

2 curtidas

A resposta curta é que o Discourse não pode contornar suas regras de firewall e o lugar para fazer perguntas estúpidas sobre coisas de sistema operacional é em algum lugar como o Stack Exchange. (Por favor, não me ache rude. É aí que essas respostas se encontram. Depois de usar Linux desde os primeiros lançamentos, eu ainda vou a lugares como esse para todas as minhas perguntas estúpidas. Eu ainda as tenho!)

3 curtidas

Eu conheço o lugar :wink: Existe uma relação sinal/ruído muito alta. Bem, essa foi uma caracterização injusta, mas eu quis dizer que é realmente difícil encontrar coisas relevantes lá. É tão massivo.

2 curtidas

Esta é, na verdade, uma pergunta muito boa e uma que me surpreende que ninguém mais ainda tenha feito. A resposta é complicada, mas até agora as respostas sobre este tópico foram, infelizmente, de tom desdenhoso sem responder à pergunta.

Não é que o Discourse esteja contornando o ufw, mas sim que o docker contorna o ufw adicionando regras que fazem com que as portas expostas dos contêineres docker funcionem apesar da presença do ufw.

O que está acontecendo?

Os pacotes de entrada destinados a um contêiner atingem a tabela FORWARD, não a tabela INPUT como se poderia esperar.

Instalação pré-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

Pós-instalação do 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

A razão pela qual os pacotes atingem a tabela forward é devido às regras que o docker adiciona à tabela 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

O nat/PREROUTING é processado antes da decisão ser tomada sobre se os pacotes devem ser enviados através de INPUT ou FORWARD.

Em última análise, o problema é que existem dois serviços no sistema modificando as regras do firewall. O ufw não sabe de nada disso, então ele só pode relatar o que ele configurou.

Uma solução

Para isso, é reconfigurar o firewall para que o tráfego destinado ao docker também passe pelas cadeias do ufw:

Eu uso a seguinte adaptação ligeira do trabalho deles, colocada em vigor antes de habilitar o ufw:

# roubado de https://github.com/chaifeng/ufw-docker - parece sensato
# adicionar o forward para ufw-user-input permite conexões para
# portas encaminhadas que explicitamente abrimos
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
20 curtidas

Obrigado! Essa foi uma explicação completa.

4 curtidas

Bem-vindo, é assim que eu faço :smiley:

6 curtidas

Este tópico foi resolvido, mas revelou um pequeno problema em minha configuração. Vou explicá-lo caso alguém pesquise algo semelhante no futuro.

Eu tinha um VPS onde o Nginx cuidava do SSL e de outras coisas de todos os meus sites (muitas coisas, o inglês é uma língua muito estranha :wink: ). O Nginx envia requisições para o Varnish. É um proxy reverso inútil para o Discourse, mas faz alguma filtragem. O Varnish envia requisições para outro VPS onde o Discourse reside usando a porta 83. Ambos os VPS escutam a mesma porta e isso é permitido apenas para ambos os IPs. Eu estava totalmente feliz — até agora.

Eu testei o que acontece quando usei a porta 443 curl -I https://forum.example.tld:443. Funcionou bem, porque eu ainda tenho um certificado SSL válido no lado do Discourse (fiz essa alteração há algumas semanas).

A resposta do @supermathie explica por que isso acontece e como corrigi-lo. Claro, não há problemas de segurança por causa disso, tanto quanto sei, mas é realmente irritante :squinting_face_with_tongue:

2 curtidas

Uau. Isso é algo muito louco! Obrigado

Eu acho que isso não é perguntado porque não é frequente que alguém instale o discourse e queira que ele não funcione, então quando o docker faz funcionar quando você configurou o firewall de tal forma que não deveria, a maioria das pessoas não reclama. :wink:

É uma questão muito interessante, mas parece um pouco esotérica, e não é um problema do Discourse, mas uma peculiaridade do docker. A questão se resume a “como posso configurar meu firewall para impedir que o discourse funcione?” Vou tentar me lembrar dessa coisa de prerouting.

Se eu soubesse a resposta, não teria sido desdenhoso! :wink: obrigado por salvar o dia nesta questão!

6 curtidas

Eu certamente não estava tentando ser desdenhoso, mas sim solucionar problemas… embora, evidentemente, eu estivesse partindo de uma posição de ignorância sobre o que o Docker estava fazendo. Todas essas são informações muito úteis, obrigado por responder!

Se o OP ou outra pessoa puder alterá-lo, pode valer a pena mudar a solução marcada.

Embora seja mais uma coisa do Docker, posso ver alguns hipotéticos do Discourse que surgem disso. Por exemplo, eu poderia ter um servidor de escritório que é acessível do mundo, mas quero configurar o UFW para restringir o Discourse a ser acessível apenas de dentro do escritório. As adições do Docker impediriam essa configuração.

Embora, nesse cenário específico, eu o configuraria em um firewall de hardware/hipervisor em vez do UFW no host de qualquer maneira.

5 curtidas

Acabei de chegar ao mesmo repositório git que você encontrou, investigando um problema ufw/docker, isso me fez pensar neste tópico.

O que exatamente você mudou (quero dizer, posso ver as linhas adicionadas, mas o que isso significa?), e essas mudanças são especificamente para o Discourse?

Usei o código padrão no repositório e meu problema com UFW parece ter sido corrigido depois disso.

EDIT: Quando uso seu código editado, no primeiro momento em que executo ufw reload, recebo o seguinte erro:

ERRO: Não foi possível carregar as regras de log

1 curtida

Na verdade, descobri depois de um tempo e escrevi este script bash para fazer a tarefa para instalações do Discourse.

Ele redefine seu firewall, instala ufw-docker-util (que edita o after.rules) e, em seguida, adiciona as portas 443 e 80 à sua lista de permissões. Pronto.

Ele também permite a porta 22 de qualquer IP para garantir que você não fique bloqueado. Depois que tudo funcionar, proteja a porta 22 novamente.

EDIT: o script funciona, mas a reconstrução do discourse após usá-lo falhará: fatal: unable to access 'https://github.com/discourse/discourse.git/': Could not resolve host: github.com - portanto, NÃO use o script, a menos que você saiba como resolver isso.

EDIT 2: Funciona no Ubuntu, mas não no CentOS!

3 curtidas

Da última vez que fiz um script bash, alterei o proprietário de todos os diretórios para www-data:www-data — então, para mim, um pedaço de trabalho como este torna a vida um pouco mais fácil :wink:

Mas, em geral — eu gostaria de ver o docker seguindo totalmente UFW/iptables. Só porque estou usando bloqueio GeoIP via iptables (sim, eu sei — UFW é apenas uma interface minimalista para iptables).

Claro, não estamos mais no Discourse, mas aqui podemos ver por que codificadores e usuários finais não conseguem se entender sempre tão bem: codificadores veem o mundo como blocos lógicos e construções if/then/else, mas usuários finais o veem como contexto completo. Significa — porque eu uso Discourse, mesmo que funcione dentro do docker, do meu ponto de vista é o Discourse que não segue minhas regras :rofl:

Isso deveria ir para Praise, mas mudei a url do fórum algumas semanas atrás. E recebi todos os script kiddies do mundo e bots de SEO inúteis para visitar. Recebi em um VPS de 2 GB/1 vcpu da DigitalOcean 3000 user agents diferentes por hora e o Discourse simplesmente não se importou. Qualquer instalação do WordPress ficaria lenta/fora do ar após esse tipo de rush ddos.

Então, eu não preciso realmente forçar o discourse (bem, o docker) a seguir os bans do Fail2ban e minhas regras — mas eu odeio esses bots tão profundamente.

3 curtidas