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
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.
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
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.
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)?
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!)
Eu conheço o lugar 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.
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
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 ). 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
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.
É 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! obrigado por salvar o dia nesta questão!
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.
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:
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.
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
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
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.