- 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
Comentários do Hacker News
Em 2024, é melhor configurar LocalForward, RemoteForward e ProxyJump no
~/.ssh/configdo que ficar escrevendo comandos SSH longos manualmenteIsso economiza bastante tempo ao acessar, com
ssh,scpersync, servidores remotos que exigem passar por várias conexões SSH intermediáriasPor exemplo, você pode encadear
jump-host-1,jump-host-2ejump-host-3comProxyJumpe então se conectar aotarget-serverusando um aliasLocalForward 0.0.0.0:8080 0.0.0.0:80encaminha a porta 80 remota para a 8080 local, eRemoteForward 0.0.0.0:9022 0.0.0.0:22encaminha requisições SSH que chegam à 9022 remota para a 22 localEm
LocalForwardeRemoteForward, o lado esquerdo é o servidor de destino e o direito é o local, e também há a dica de usar0.0.0.0em vez delocalhostou127.0.0.1ssh_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 foraCom 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 viaarpnão bater com o valor esperado, faz usarProxyJump jump.example.orgA ordem é importante: primeiro detectar a VPN/rede de casa e depois aplicar o jump host quando estiver fora
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
0.0.0.0pode ser perigosoIsso 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
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
bash/fishpara que eu só precise lembrar do mínimo de argumentosSe 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 é poderosoSe você executar
ssh -D 8888 someservere configurar o proxy SOCKS do navegador paralocalhost:8888, todo o tráfego do navegador será roteado porsomeserverO Firefox ainda permite fazer isso sem alterar o padrão do sistema, o que é muito útil
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
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
~/.ssh/confige ProxyJump, dá para “pular” por quantas etapas forem necessárias, como A, B, C, D e EOs 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
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
-JEm 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
Se você usar
sshuttle, tunneling fica bem mais fácilUsando algo como
sshuttle -r user@host 10.0.0.0/8, a faixa10/8é tunelada automaticamente e, na prática, funciona como uma VPN sobre SSHFico 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
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
Caso contrário, basta usar a função de jump:
ssh -J B CSe 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
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