6 pontos por GN⁺ 2024-09-20 | 1 comentários | Compartilhar no WhatsApp
  • O tunelamento SSH transporta tráfego TCP sobre uma conexão SSH segura e é usado para abrir, com segurança, caminhos restritos, como criptografar protocolos legados, acessar painéis de administração e conectar a servidores atrás de NAT
  • No lado do servidor, é necessário AllowTcpForwarding yes; para abrir portas em interfaces que não sejam loopback, é preciso configurar GatewayPorts yes e reiniciar o servidor SSH
  • ssh -J, ssh -L, ssh -R e ssh -D cuidam, respectivamente, de jump host, encaminhamento local, encaminhamento remoto e encaminhamento dinâmico baseado em SOCKS5
  • Para manter o túnel em segundo plano, use ssh -fN; a detecção de queda é ajustada com configurações de heartbeat, como ClientAliveInterval e ClientAliveCountMax
  • O tunelamento SSH não oferece suporte direto a UDP e pode sofrer problemas de latência e throughput em TCP-over-TCP; portanto, é mais uma ferramenta para abrir caminhos TCP específicos do que um substituto de VPN

Situações para usar tunelamento SSH

  • Tunelamento SSH e encaminhamento de portas transmitem tráfego TCP do cliente para o servidor, ou do servidor para o cliente, por meio de uma conexão SSH
  • É possível usar portas TCP e sockets UNIX, mas os exemplos se concentram em portas TCP
  • Os usos mais comuns se dividem em segurança, solução de problemas e contorno de conectividade
    • Segurança
      • Criptografar conexões inseguras, como FTP, ou protocolos legados
      • Acessar painéis de administração web por meio de um túnel SSH com autenticação por chave pública
      • Manter exposta apenas a porta 22, sem abrir portas adicionais como 80/443
    • Solução de problemas
      • Contornar firewalls ou filtros de conteúdo
      • Escolher uma rota de rede diferente
    • Conectividade
      • Acessar servidores atrás de NAT
      • Entrar em servidores internos a partir da internet por meio de um jump host
      • Expor uma porta local à internet

Configurações a verificar antes do encaminhamento de portas

  • As opções dos exemplos podem ser combinadas e configuradas de acordo com o ambiente
  • Se bind_address não for especificado, o padrão é localhost
  • Usuários locais e remotos precisam ter permissão para abrir portas em suas respectivas máquinas
    • As portas 0-1024 exigem privilégios de root, salvo configuração específica em contrário
    • As demais portas também podem ser configuradas por usuários comuns
    • O cliente e os firewalls de rede também precisam estar abertos de acordo com o caminho de encaminhamento
  • No servidor SSH, o encaminhamento de portas precisa estar habilitado
    • AllowTcpForwarding yes
    • Em muitos casos ele vem habilitado por padrão, mas é necessário verificar a configuração do servidor
  • Para encaminhar uma porta por uma interface que não seja 127.0.0.1, habilite GatewayPorts no servidor SSH
    • GatewayPorts yes
    • Depois da configuração, é preciso reiniciar o serviço do servidor SSH

Jump host SSH e túneis em múltiplas etapas

  • ssh -J é usado para se conectar de forma transparente a um host remoto passando por um ou mais hosts
ssh -J user@REMOTE-MACHINE:22 -p 22 user@10.99.99.1
  • Ao usar a porta padrão 22, a indicação da porta pode ser omitida
  • Ao usar REMOTE-MACHINE como jump host, a conexão é confirmada da seguinte forma
[user@REMOTE-MACHINE]$ ss | grep -i ssh
tcp ESTAB 0 0 167.135.173.108:ssh 192.160.140.207:45960
tcp ESTAB 0 0 10.99.99.2:49770 10.99.99.1:ssh
  • Os papéis dos endereços de exemplo são os seguintes
    • 167.135.173.108: IP público da REMOTE-MACHINE
    • 192.160.140.207: IP público da LOCAL-MACHINE
    • 10.99.99.2: IP interno da REMOTE-MACHINE
    • 10.99.99.1: IP interno da REMOTE-WEBAPP
  • Ao usar vários jump hosts, separe-os por vírgulas
ssh -J user@REMOTE-MACHINE:22,user@ANOTHER-REMOTE-MACHINE:22 -p 22 user@10.99.99.1

Encaminhamento de porta local

  • O encaminhamento de porta local usa a opção ssh -L
  • O primeiro exemplo encaminha 10.10.10.1:8001 da LOCAL-MACHINE para localhost:8000 da REMOTE-MACHINE
ssh -L 10.10.10.1:8001:localhost:8000 user@REMOTE-MACHINE
  • O log de acesso do servidor web na REMOTE-MACHINE, vinculado apenas a 127.0.0.1, aparece assim
127.0.0.1 - - [30/Dec/2022 18:05:15] "GET / HTTP/1.1" 200
  • Essa requisição é iniciada na LOCAL-MACHINE
  • O segundo exemplo encaminha a porta local 8001 para 10.99.99.1:8000 por meio da REMOTE-MACHINE
ssh -L 8001:10.99.99.1:8000 user@REMOTE-MACHINE
  • No log de acesso do servidor web da REMOTE-WEBAPP, a requisição aparece como vinda do IP interno da REMOTE-MACHINE
10.99.99.2 - - [30/Dec/2022 21:28:42] "GET / HTTP/1.1" 200

Encaminhamento de porta remota

  • O encaminhamento de porta remota usa a opção ssh -R
  • Os exemplos encaminham a porta 8000 da REMOTE-MACHINE para localhost:8001 ou 10.10.10.2:8001 no lado local
ssh -R 8000:localhost:8001 user@REMOTE-MACHINE
ssh -R 8000:10.10.10.2:8001 user@REMOTE-MACHINE
  • Também é possível configurar o recebimento em uma interface remota específica, 10.99.99.2:8000
ssh -R 10.99.99.2:8000:10.10.10.2:8001 user@REMOTE-MACHINE
  • Para receber conexões em uma interface que não seja loopback, o servidor SSH precisa estar com GatewayPorts yes habilitado

Encaminhamento de porta dinâmico e SOCKS5

  • Ao encaminhar várias portas, o SSH usa o protocolo SOCKS
  • SOCKS é um protocolo de proxy transparente, e o SSH usa a versão mais recente, SOCKS5
  • A porta padrão de um servidor SOCKS5 é 1080, definida na RFC 1928
  • O cliente precisa ser configurado para usar o proxy SOCKS na camada de aplicação ou na camada do sistema operacional
  • O exemplo com ssh -D abre um proxy SOCKS em 10.10.10.1:5555
ssh -D 10.10.10.1:5555 user@REMOTE-MACHINE
  • No cliente LOCAL, é possível testar o caminho da conexão com curl
curl -L -x socks5://10.10.10.1:5555 brrl.net/ip
  • Se estiver funcionando corretamente, o IP público da REMOTE-MACHINE será retornado

Tunelamento SSH TUN/TAP

  • É possível criar um túnel bidirecional com a flag -w
  • As interfaces precisam ter sido criadas previamente
  • Permanece a ressalva de que esse método não foi testado
-w local_tun[:remote_tun]

Execução em segundo plano e encerramento

  • Para executar um túnel em segundo plano de forma nativa, use -fN
    • -f: execução em segundo plano
    • -N: não abre um shell
ssh -fN -L 8001:127.0.0.1:8000 user@REMOTE-MACHINE
  • Como alternativa, é possível usar screen ou outras ferramentas
  • Para encerrar um SSH em execução em segundo plano, encontre o processo e finalize-o pelo PID
user@pleasejustwork:~$ ps -ef | grep ssh
[...]
user 19255 1 0 11:40 ? 00:00:00 ssh -fN -L 8001:127.0.0.1:8000 user@REMOTE-MACHINE
[...]
kill 19255

Manutenção da conexão SSH e reconexão

  • Há várias formas de manter uma conexão SSH ativa
  • Opções de heartbeat para tratar timeouts podem ser configuradas no cliente, no servidor ou em ambos
  • ClientAliveInterval envia uma requisição a cada n segundos para manter a conexão ativa
ClientAliveInterval 15
  • ClientAliveCountMax é o número de requisições de heartbeat enviadas antes de encerrar a conexão depois de não receber resposta da outra ponta
ClientAliveCountMax 3
  • 3 é o valor padrão; definir como 0 desativa o encerramento da conexão
  • Na configuração do exemplo, a conexão é encerrada após cerca de 45 segundos sem resposta
  • Para reconectar após o encerramento da conexão, é possível usar autossh, scripts, cronjob etc.

Limitações e cuidados de segurança

  • UDP

    • O SSH depende de uma transmissão confiável para a descriptografia correta
    • UDP não oferece confiabilidade, por isso não é suportado nem recomendado em túneis SSH
    • Existe um método que trata de UDP over SSH tunneling, mas há a ressalva de que ele não foi testado
  • TCP-over-TCP

    • O overhead reduz o throughput e aumenta a latência
    • Em conexões com perda de pacotes ou alta latência, pode ocorrer TCP meltdown
    • Também é possível consultar o artigo sobre TCP over TCP
    • Ao usar OpenVPN-over-TCP por algum tempo, o throughput foi menor que com UDP, mas funcionou de forma estável; o resultado depende muito da configuração
  • Limitações ao usar como substituto de VPN

    • Embora seja possível usar tunelamento SSH como uma VPN, VPNs são mais adequadas para obter melhor desempenho
  • Riscos de segurança

    • Se esse recurso não for necessário, recomenda-se desativá-lo
    • Um invasor pode usar tunelamento SSH e encaminhamento de portas para contornar firewalls e outros mecanismos de segurança
  • Documentação de referência

1 comentários

 
GN⁺ 2024-09-20
Comentários do Hacker News
  • Em 2024, é melhor configurar LocalForward, RemoteForward e ProxyJump no ~/.ssh/config do que ficar escrevendo comandos SSH longos manualmente
    Isso economiza bastante tempo ao acessar, com ssh, scp e rsync, servidores remotos que exigem passar por várias conexões SSH intermediárias
    Por exemplo, você pode encadear jump-host-1, jump-host-2 e jump-host-3 com ProxyJump e então se conectar ao target-server usando um alias
    LocalForward 0.0.0.0:8080 0.0.0.0:80 encaminha a porta 80 remota para a 8080 local, e RemoteForward 0.0.0.0:9022 0.0.0.0:22 encaminha requisições SSH que chegam à 9022 remota para a 22 local
    Em LocalForward e RemoteForward, o lado esquerdo é o servidor de destino e o direito é o local, e também há a dica de usar 0.0.0.0 em vez de localhost ou 127.0.0.1

    • Compartilhando uma dica de ssh_config: é útil montar uma configuração que desvie automaticamente para SSH direto em cada máquina quando você está em casa ou dentro de uma VPN auto-hospedada, e use um jump host quando estiver fora
      Com algo como Match host *.example.org exec "getent ahosts router.example.org | grep -q ^10.0.0.1", primeiro se detecta se está em casa/VPN pelo endereço do roteador, e se o endereço MAC via arp não bater com o valor esperado, faz usar ProxyJump jump.example.org
      A ordem é importante: primeiro detectar a VPN/rede de casa e depois aplicar o jump host quando estiver fora
    • Às vezes é algo que você vai usar só uma vez e acabou, então não dá vontade de criar até um arquivo de configuração
      Se for para criar um VPS de curta duração e usar SSH como proxy SOCKS para contornar restrições regionais, ou entrar uma única vez em um servidor que você normalmente não acessa para ajudar outra equipe rapidamente, opções de linha de comando parecem melhores
    • Usar 0.0.0.0 pode ser perigoso
      Isso pode abrir a porta em todas as interfaces de rede e, principalmente se o servidor remoto não tiver firewall, acabar expondo algo para a internet inteira
      Para tunelamento ou encaminhamento de porta usados com frequência, arquivo de configuração é melhor, mas para tarefas únicas ou raras, opções de linha de comando parecem melhores
    • Fiquei curioso sobre como as pessoas gerenciam esse tipo de configuração SSH para padronizar e distribuir em várias máquinas locais
      Estou procurando algo parecido com GitOps que sirva para um único usuário em várias máquinas e permita buscar a configuração de um lugar como o GitHub, sem precisar manter um servidor dedicado sempre ligado
    • Nem sempre quero que um shell seja aberto, então criei funções básicas em bash/fish para que eu só precise lembrar do mínimo de argumentos
      Se eu esquecer, basta olhar a definição da função, que deixei documentada
  • No ambiente corporativo absurdo em que trabalho, tunelamento SSH é essencial
    Às vezes leva semanas para conseguir permissões de acesso, abrir portas ou obter exceções de firewall/VPN por causa da burocracia
    Este artigo menciona -D, mas não explica bem o quanto isso é poderoso
    Se você executar ssh -D 8888 someserver e configurar o proxy SOCKS do navegador para localhost:8888, todo o tráfego do navegador será roteado por someserver
    O Firefox ainda permite fazer isso sem alterar o padrão do sistema, o que é muito útil

    • Em meados dos anos 2000, isso era praticamente o padrão para navegar na web quando se estava fora de casa
      Mas, ao entrar na empresa, descobri que por causa de listas de permissões por IP eu nem conseguia abrir uma conexão SSH para um servidor qualquer na internet; foi tão sofrido que comecei até a pesquisar como montar um túnel HTTP e colocar um servidor sob meu controle na lista de permissões, mas no fim troquei de emprego
    • Não é uma boa ideia contornar redes corporativas
      Essas restrições existem por um motivo, e tentar burlá-las pode parecer falta de conhecimento e desrespeito aos processos da organização e à especialização em segurança
      Se levar semanas ou meses para obter acesso, então esse é o tempo que você terá de esperar, e você provavelmente não vai querer assumir a responsabilidade de abrir um backdoor para informações confidenciais ou comprometer a segurança
  • A gambiarra mais suja com tunelamento SSH que já fiz às 3 da manhã foi ligar três datacenters
    Três instalações na mesma região metropolitana tinham conexão com a internet upstream, mas por políticas de roteamento estranhas o A só conseguia falar com B, e só o B conseguia falar com C
    No fim, para mover dados de A para C passando por B, tive de misturar rsync + túnel SSH + chaves + truques de roteamento, e depois de ajustar alguns comandos meio no chute, ver tudo funcionar de uma vez pareceu mágica
    Hoje parece muito óbvio como eu faria isso, mas na época, como iniciante, foi uma grande conquista, e ainda lembro da adrenalina de confirmar que a sincronização tinha terminado

    • Com ~/.ssh/config e ProxyJump, dá para “pular” por quantas etapas forem necessárias, como A, B, C, D e E
  • Os detalhes da visualização são bons
    Em redes, mais ainda do que em outras áreas, eu gostaria que existissem muito mais ferramentas para representar visualmente o tráfego em níveis mais baixos de conexão

    • Estes diagramas aqui também valem a pena: https://www.nathanhandy.blog/articles/osi-model-revisited.ht...
      Claro, é só uma representação estática de conceitos, e a maioria dos fornecedores de rede também oferece algum tipo de visualização de tráfego, mas normalmente isso fica no nível de métricas ou gráficos isolados
  • Se um servidor Linux ou um dispositivo IoT estiver atrás de um firewall e sem IP fixo, mas você quiser acessá-lo por SSH, pode usar um serviço de tunelamento como https://sshreach.me

  • Usei tunelamento bastante ao longo de alguns anos, mas não conhecia a opção -J
    Em vez de perder 30 minutos configurando isso cada vez que preciso de um túnel, algo que acontece a cada poucos meses, eu gostaria que existisse uma ferramenta visual para montar o túnel

  • Há uma explicação de que TCP-over-TCP aumenta a sobrecarga, reduz a vazão, eleva a latência e pode causar colapso de TCP em conexões com perda de pacotes ou alta latência, como links via satélite
    Mas, em túneis SSH, isso na prática não costuma ser um problema, a menos que se use TAP/TUN
    Isso porque o SSH desfaz o fluxo TCP e o encaminha
    Ainda assim, ao usar vários canais, o desempenho pode cair por causa de head-of-line blocking

  • Aprendi SSH tunneling há cerca de 15 anos para contornar o firewall da rede da universidade, e precisei mudar a porta padrão para 443
    Desde então, continuo usando isso para finalidades muito mais variadas do que apenas burlar firewall

    • Fico curioso para saber em que outros usos, além de contornar firewall ou expor serviços locais pela rede, as pessoas acharam isso útil
  • Se você usar sshuttle, tunneling fica bem mais fácil
    Usando algo como sshuttle -r user@host 10.0.0.0/8, a faixa 10/8 é tunelada automaticamente e, na prática, funciona como uma VPN sobre SSH

  • Fico me perguntando se o próprio SSH tem algum recurso de redirecionamento
    Por exemplo, se A tentar fazer SSH em B, B avisar para se conectar a C, e A passar a se conectar diretamente a C de forma transparente, sem que B permaneça no caminho principal dos dados

    • Parece que daria para fazer algo parecido com um IP virtual
      Meu firewall/roteador não repassa corretamente a opção 67 do DHCP e sempre envia o próprio endereço, então precisei configurar um IP virtual/regra para que, quando o tráfego de boot PXE daquela porta fosse para o IP do roteador, ele fosse roteado até o servidor real de boot PXE
    • Se A não souber que o destino real é C, isso pode ser enganoso
      Caso contrário, basta usar a função de jump: ssh -J B C
      Se não for necessário que B esteja no caminho e for possível conectar diretamente a C, então é só conectar direto a C; se isso não for possível, de qualquer forma B terá de entrar como hop
    • B até poderia encaminhar portas para C, isto é, rotear os pacotes, mas não parece haver um equivalente a um redirecionamento permanente como no HTTP
      Se você explicar melhor o problema, talvez exista uma solução mais adequada
      Em um host com certo grau de embarcação, talvez o DNS possa assumir o “roteamento”, mas nesse caso a verificação da impressão digital da chave do host teria de ser tratada manualmente