Existe um proxy reverso SSH do host virtual baseado em nome?

36

Gostei bastante de proxies reversos HTTP em nosso ambiente de desenvolvimento e achei o proxy reverso de host virtual baseado em DNS bastante útil. Ter apenas uma porta (e a padrão) aberta no firewall facilita muito o gerenciamento.

Gostaria de encontrar algo semelhante para fazer conexões SSH, mas não tive muita sorte. Prefiro não usar simplesmente o encapsulamento SSH, pois isso exige a abertura de intervalos de portas diferentes do padrão. Existe algo lá fora que possa fazer isso?

O HAProxy poderia fazer isso?

ahanson
fonte
A transferência de arquivos do aplicativo pretendida ou o acesso SSH real aos hosts?
Kyle Hodgson
O acesso SSH direto ao host é o objetivo. Essa necessidade vem do desejo de executar um servidor Mercurial internamente, mas nosso servidor está atrás do firewall. No momento, estou trabalhando para configurar simplesmente uma versão HTTP, mas queria que os commits usassem SSH em vez de HTTP. O acesso SSH direto a outros servidores seria um bônus, se isso fosse possível.
Ahanson 01/07/2009
Este é um problema tão irritante.
viés
Meu entendimento é que o HAProxy agora suporta isso via SNI. Embora eu não tenha conseguido fazer isso ainda.
Carel

Respostas:

24

Não acredito que o SSH baseado em nome seja algo possível, considerando o funcionamento do protocolo.

Aqui estão algumas alternativas.

  • Você poderia fazer é configurar o host que responde pela porta 22 para atuar como um gateway. Em seguida, você pode configurar o servidor ssh para encaminhar solicitações para o interior com base na chave. Exemplo de gateway SSH com chaves

  • Você pode ajustar seu cliente para usar esse host como proxy. Ou seja, seria ssh para o host do gateway e, em seguida, utilizaria esse host para estabelecer uma conexão com o host interno. Proxy SSH com configuração do cliente .

  • Você também pode configurar um proxy HTTP simples na borda. Em seguida, use isso para permitir conexões de entrada. SSH via proxy HTTP .

Obviamente, com todas as opções acima, certifique-se de configurar e bloquear corretamente o gateway é muito importante.

Zoredache
fonte
18

Eu tenho procurado uma solução para este problema dentro e fora nos últimos 16 meses. Mas, cada vez que olho, parece impossível fazer isso com o protocolo SSH, conforme especificado nas RFCs relevantes e implementado pelas principais implementações.

No entanto, se você estiver disposto a usar um cliente SSH levemente modificado e estiver disposto a utilizar protocolos de maneira que não foi exatamente planejada quando eles foram projetados, é possível obter isso. Mais sobre isso abaixo.

Por que não é possível

O cliente não envia o nome do host como parte do protocolo SSH.

Ele pode enviar o nome do host como parte de uma pesquisa de DNS, mas isso pode ser armazenado em cache, e o caminho do cliente através dos resolvedores para servidores autoritativos pode não cruzar o proxy e, mesmo que isso ocorra, não existe uma maneira robusta de associar pesquisas de DNS específicas a clientes SSH específicos.

Também não há nada que você possa fazer com o próprio protocolo SSH. Você precisa escolher um servidor sem ter visto o banner da versão SSH do cliente. Você precisa enviar um banner para o cliente, antes que ele envie qualquer coisa para o proxy. Os banners dos servidores podem ser diferentes e você não tem chance de adivinhar qual é o correto para usar.

Mesmo que este banner seja enviado sem criptografia, você não pode modificá-lo. Cada parte desse banner será verificada durante a configuração da conexão; portanto, você estará causando uma falha na conexão um pouco abaixo da linha.

A conclusão para mim é bastante clara: é preciso mudar algo no lado do cliente para fazer essa conectividade funcionar.

A maioria das soluções alternativas está encapsulando o tráfego SSH dentro de um protocolo diferente. Pode-se também imaginar uma adição ao próprio protocolo SSH, no qual o banner da versão enviado pelo cliente inclui o nome do host. Isso pode permanecer compatível com os servidores existentes, já que parte do banner está atualmente especificada como um campo de identificação de formulário livre e, embora os clientes normalmente esperem o banner de versão do servidor antes de enviar o seu próprio, o protocolo permite que o cliente envie seu banner primeiro. Algumas versões recentes do cliente ssh (por exemplo, no Ubuntu 14.04) enviam o banner sem aguardar o banner do servidor.

Não conheço nenhum cliente que tenha tomado medidas para incluir o nome do host do servidor nesse banner. Enviei um patch para a lista de discussão do OpenSSH para adicionar esse recurso. Mas foi rejeitado com base no desejo de não revelar o nome do host a ninguém bisbilhotando no tráfego SSH. Como um nome de host secreto é fundamentalmente incompatível com a operação de um proxy baseado em nome, não espere ver uma extensão SNI oficial para o protocolo SSH tão cedo.

Uma solução real

A solução que melhor funcionou para mim foi usar o IPv6.

Com o IPv6, posso ter um endereço IP separado atribuído a cada servidor, para que o gateway possa usar o endereço IP de destino para descobrir para qual servidor enviar o pacote. Às vezes, os clientes SSH podem estar em execução nas redes em que a única maneira de obter um endereço IPv6 seria usando o Teredo. Sabe-se que o Teredo não é confiável, mas apenas quando o final do IPv6 nativo da conexão está usando uma retransmissão pública do Teredo. Pode-se simplesmente colocar um relé Teredo no gateway, onde você executaria o proxy. O Miredo pode ser instalado e configurado como um relé em menos de cinco minutos.

Uma solução alternativa

Você pode usar um host de salto / host de bastião. Essa abordagem é direcionada para casos em que você não deseja expor a porta SSH dos servidores individuais diretamente à Internet pública. Ele tem o benefício adicional de reduzir o número de endereços IP externos que você precisa para SSH, e é por isso que é utilizável nesse cenário. O fato de ser uma solução destinada a adicionar outra camada de proteção por motivos de segurança não impede que você a use quando não precisar da segurança adicionada.

ssh -o ProxyCommand='ssh -W %h:%p user1@bastion' user2@target

Um truque sujo para fazê-lo funcionar se a solução real (IPv6) estiver fora do seu alcance

O truque que estou prestes a descrever deve ser usado apenas como o último recurso. Antes mesmo de pensar em usar esse hack, recomendo fortemente obter um endereço IPv6 para cada um dos servidores que você deseja alcançar externamente através do SSH. Use o IPv6 como método principal para acessar seus servidores SSH e use esse hack apenas quando precisar executar um cliente SSH a partir de uma rede somente IPv4, onde você não tem nenhuma influência sobre a implantação do IPv6.

A ideia é que o tráfego entre o cliente e o servidor precise ser um tráfego SSH perfeitamente válido. Mas o proxy só precisa entender o suficiente sobre o fluxo de pacotes para identificar o nome do host. Como o SSH não define uma maneira de enviar um nome de host, você pode considerar outros protocolos que oferecem essa possibilidade.

HTTP e HTTPS permitem que o cliente envie um nome de host antes que o servidor envie quaisquer dados. A questão agora é se é possível construir um fluxo de bytes que seja simultaneamente válido como tráfego SSH e como HTTP e HTTPS. HTTPs é praticamente um não iniciador, mas HTTP é possível (para definições suficientemente liberais de HTTP).

SSH-2.0-OpenSSH_6.6.1 / HTTP/1.1
$: 
Host: example.com

Isso parece SSH ou HTTP para você? É SSH e completamente compatível com RFC (exceto que alguns dos caracteres binários foram distorcidos um pouco pela renderização do SF).

A cadeia de caracteres da versão SSH inclui um campo de comentário, que acima tem o valor / HTTP/1.1. Após a nova linha, o SSH possui alguns dados binários do pacote. O primeiro pacote é uma MSG_SSH_IGNOREmensagem enviada pelo cliente e ignorada pelo servidor. A carga útil a ser ignorada é:

: 
Host: example.com

Se um proxy HTTP for suficientemente liberal no que aceita, a mesma sequência de bytes será interpretada como um método HTTP chamado SSH-2.0-OpenSSH_6.6.1e os dados binários no início da mensagem de ignorar serão interpretados como um nome de cabeçalho HTTP.

O proxy não entenderia nem o método HTTP nem o primeiro cabeçalho. Mas ele pode entender o Hostcabeçalho, que é tudo o que precisa para encontrar o back-end.

Para que isso funcione, o proxy teria que ser projetado com o princípio de que ele precisa entender apenas HTTP suficiente para encontrar o back-end e, uma vez encontrado o back-end, o proxy simplesmente passará o fluxo de bytes brutos e deixará a real terminação. da conexão HTTP a ser feita pelo back-end.

Pode parecer um pouco exagerado fazer tantas suposições sobre o proxy HTTP. Mas se você estava disposto a instalar um novo software desenvolvido com a intenção de oferecer suporte ao SSH, os requisitos para o proxy HTTP não parecem muito ruins.

No meu próprio caso, achei que esse método funcionava em um proxy já instalado, sem alterações no código, na configuração ou de outra forma. E isso foi para um proxy escrito com apenas HTTP e sem SSH em mente.

Prova de conceito cliente e proxy . (Isenção de responsabilidade de que o proxy é um serviço operado por mim. Sinta-se à vontade para substituir o link depois que qualquer outro proxy for confirmado para suportar esse uso.)

Advertências deste hack

  • Não use. É melhor usar a solução real, que é o IPv6.
  • Se o proxy tentar entender o tráfego HTTP, ele certamente será interrompido.
  • Confiar em um cliente SSH modificado não é bom.
Kasperd
fonte
Você pode elaborar o que você quer dizer com the gateway can use the destination IP address to find out which server to send the packet to, na solução IPv6?
Jacob Ford
@JacobFord A chave para entender essa frase é que eu uso a palavra gateway, não proxy . Com o IPv6, você obtém endereços IP suficientes para atribuir um a cada host e ainda tem endereços de sobra. Todas as máquinas que você colocaria atrás do proxy teriam seu próprio endereço IP, para o qual você resolveria os nomes. Para que você não precise mais de um proxy, os clientes enviam o tráfego para o endereço IP do host desejado e você pode rotear o tráfego diretamente para lá.
Kasperd
para a parte da solução alternativa, há uma opção de comando relativamente nova para o ssh -J, para que você possa usar: ssh -J user1 @ front user2 @ target
PMN
3

Não acredito que isso seja possível, pelo menos da maneira que você descreveu, embora eu adorasse provar que estou errado. Não parece que o cliente envie o nome do host ao qual deseja se conectar (pelo menos de forma clara). A primeira etapa da conexão SSH parece ser configurar a criptografia.

Além disso, você teria problemas com a verificação da chave do host. Os clientes SSH verificarão as chaves com base em um endereço IP e também em um nome de host. Você teria vários nomes de host com chaves diferentes, mas o mesmo IP ao qual está se conectando.

Uma solução possível seria ter um host 'bastião', no qual os clientes possam acessar a máquina, obter um shell normal (ou restrito, se desejado) e, em seguida, transferir para hosts internos a partir daí.

Marca
fonte
O conceito de bastião é o que temos atualmente configurado, mas é problemático para o meu controle de versão (sem esforço extra).
Ahanson 01/07/2009
É super irritante que o ssh não envie o fqdn e lide com o DNS no lado do cliente. Acho que as pessoas não se preocuparam com o inchaço de IP público e o NAT quando a maioria dos protocolos de nível de aplicativo TCP / IP foi criada. Porque, sério, você deve ser capaz de executar NAT baseado em FQDN com iptables (por exemplo, filtros do kernel).
viés
A chave do host pode ser a chave do proxy reverso. Esse é um benefício se você confia na segurança do back-end, já que possui controle da rede interna e dos hosts.
rox0r
@bias Você não pode executar o NAT com base no nome do host, mesmo que o protocolo de nível superior envie o nome do host. A razão pela qual isso não pode ser feito é que a escolha do back-end deve ser feita quando o pacote SYN é recebido, mas o nome do host é enviado apenas após o processamento do SYN e a devolução de um SYN-ACK. No entanto, você pode usar um proxy de camada de aplicativo muito fino para protocolos que enviam nome de host, como http e https.
kasperd
3

Há um garoto novo no quarteirão. O SSH piper roteará sua conexão com base em nomes de usuário predefinidos, que devem ser mapeados para os hosts internos. Esta é a melhor solução no contexto do proxy reverso.

Piper SSh no github

Meus primeiros testes confirmaram, SSH e SFTP funcionam.

Király István
fonte
Isso é efetivamente um ataque MITM. Espero que ele interrompa todas as configurações protegidas contra ataques MITM.
kasperd
1
Na verdade, a parte anfitriã é ao mesmo tempo o anfitrião e o homem do meio, portanto apenas esses dois estão envolvidos.
Király István
@ KirályIstván este é um projeto incrível e prova que outras respostas não estão 100% corretas. Criei uma ferramenta semelhante com base no github.com/gliderlabs/sshfront e em alguns bash / python (não consigo abrir código-fonte, mas não é tão interessante - o bash executa o ssh client e o python é usado como manipulador de autenticação). Mas eu tenho um problema com a solução atual. Ele não suporta sftp (o scp funciona). Trava tentando executar o subsistema debug1: Sending subsystem: sftp. Acontece que a frente da camisa não suporta subsistemas. Você suporta bainha no SSh piper?
Maciek Sawicki 27/03
1
@MaciekSawicki Eu não sou o autor. Eu apenas uso no meu projeto. .)
Király István
2

Gostaria de saber se Honeytrap (o honeypot de baixa interação) que tem um modo proxy não pôde ser modificado para conseguir isso.

Este honeypot pode encaminhar qualquer protocolo para outro computador. Adicionar um sistema vhost baseado em nome (conforme implementado pelo Apache) pode torná-lo um proxy reverso perfeito para qualquer protocolo, não?

Não tenho as habilidades necessárias para conseguir isso, mas talvez possa ser um ótimo projeto.

Kafeine
fonte
excelente ideia!
viés
1
O recurso vhost no Apache depende do cliente enviar o nome do host antes que qualquer dado seja enviado do servidor. O protocolo SSH não envolve esse nome de host, então não vejo como você começaria a implementar esse recurso. Mas se você puder elaborar suas idéias, eu ficaria feliz em implementar uma prova de conceito ou dizer por que não funcionaria.
kasperd
1

À medida que aumenta o número de portas / hosts que você deseja acessar por trás de um firewall, aumenta a conveniência das VPNs.

Eu não gosto de VPNs, no entanto.

alex
fonte
1

por causa de como o ssh funciona, acho que não é possível. Semelhante ao https, você teria que ter IPs (externos) diferentes para hosts diferentes, porque o gateway não sabe onde você deseja se conectar, porque tudo no ssh está criptografado

Jure1873
fonte