Esiste un proxy inverso SSH host virtuale basato sul nome?


36

Mi sono appassionato ai proxy inversi HTTP nel nostro ambiente di sviluppo e ho trovato molto utile il proxy inverso dell'host virtuale basato su DNS. Avere una sola porta (e quella standard) aperta sul firewall semplifica notevolmente la gestione.

Mi piacerebbe trovare qualcosa di simile per fare connessioni SSH ma non ho avuto molta fortuna. Preferirei non usare semplicemente il tunneling SSH poiché ciò richiede l'apertura di intervalli di porte diversi dallo standard. C'è qualcosa là fuori che può farlo?

HAProxy potrebbe farlo?


Il trasferimento di file dell'applicazione previsto o l'accesso SSH effettivo agli host?
Kyle Hodgson,

L'obiettivo è l'accesso SSH diretto all'host. Questa esigenza nasce dal desiderio di eseguire internamente un server Mercurial ma il nostro server è protetto dal firewall. In questo momento sto lavorando semplicemente alla configurazione di una versione HTTP ma volevo che i commit usassero SSH invece di HTTP. L'accesso diretto SSH ad altri server sarebbe un vantaggio se ciò fosse possibile.
ahanson,

Questo è un problema così fastidioso.
pregiudizio il

La mia comprensione è che HAProxy ora supporta questo tramite SNI. Anche se non sono ancora riuscito a farlo.
Carel,

Risposte:


24

Non credo che SSH basato sul nome sia qualcosa che sarà possibile dato il funzionamento del protocollo.

Ecco alcune alternative.

  • È possibile configurare l'host che risponde alla porta 22 affinché funga da gateway. Quindi è possibile configurare il server SSH per inoltrare le richieste all'interno in base alla chiave. Esempio di gateway SSH con chiavi

  • È possibile adattare il client in modo da utilizzare tale host come proxy. Cioè, sarebbe ssh per l'host gateway, e quindi utilizzare quell'host per stabilire una connessione all'host interno. Proxy SSH con configurazione client .

  • È inoltre possibile configurare un semplice proxy http sul bordo. Quindi utilizzalo per consentire le connessioni in entrata. SSH tramite proxy HTTP .

Ovviamente con tutto quanto sopra, assicurarsi di configurare e bloccare correttamente il gateway è piuttosto importante.


18

Ho cercato una soluzione per questo problema on e off negli ultimi 16 mesi. Ma ogni volta che guardo, sembra impossibile farlo con il protocollo SSH come specificato nelle RFC pertinenti e implementato dalle principali implementazioni.

Tuttavia, se si è disposti a utilizzare un client SSH leggermente modificato e si desidera utilizzare protocolli in un modo che non era esattamente previsto quando sono stati progettati, è possibile ottenere. Maggiori informazioni su questo sotto.

Perché non è possibile

Il client non invia il nome host come parte del protocollo SSH.

Potrebbe inviare il nome host come parte di una ricerca DNS, ma potrebbe essere memorizzato nella cache e il percorso dal client attraverso i resolver ai server autorevoli potrebbe non attraversare il proxy e anche se lo facesse non esiste un modo affidabile per associare ricerche DNS specifiche a client SSH specifici.

Non c'è niente di speciale che tu possa fare con il protocollo SSH stesso. Devi scegliere un server senza nemmeno aver visto il banner della versione SSH dal client. Devi inviare un banner al client, prima che invierà qualcosa al proxy. I banner dei server potrebbero essere diversi e non hai alcuna possibilità di indovinare quale sia quello corretto da usare.

Anche se questo banner viene inviato non crittografato, non è possibile modificarlo. Ogni bit di quel banner verrà verificato durante la configurazione della connessione, quindi potresti causare un errore di connessione un po 'lungo la linea.

La conclusione per me è abbastanza chiara, bisogna cambiare qualcosa sul lato client per far funzionare questa connettività.

La maggior parte delle soluzioni alternative incapsula il traffico SSH all'interno di un protocollo diverso. Si potrebbe anche immaginare un'aggiunta al protocollo SSH stesso, in cui il banner della versione inviato dal client include il nome host. Ciò può rimanere compatibile con i server esistenti, poiché parte del banner è attualmente specificato come campo di identificazione in formato libero e sebbene i client in genere attendono il banner versione dal server prima di inviarne uno proprio, il protocollo consente al client di inviare il proprio banner primo. Alcune versioni recenti del client ssh (ad esempio quella su Ubuntu 14.04) inviano il banner senza attendere il banner del server.

Non conosco alcun client, che ha preso provvedimenti per includere il nome host del server in questo banner. Ho inviato una patch alla mailing list di OpenSSH per aggiungere tale funzionalità. Ma è stato respinto in base al desiderio di non rivelare il nome host a nessuno ficcanaso sul traffico SSH. Poiché un nome host segreto è fondamentalmente incompatibile con il funzionamento di un proxy basato sul nome, non aspettarti di vedere presto un'estensione SNI ufficiale per il protocollo SSH.

Una vera soluzione

La soluzione che ha funzionato meglio per me era in realtà utilizzare IPv6.

Con IPv6 posso avere un indirizzo IP separato assegnato a ciascun server, così il gateway può usare l'indirizzo IP di destinazione per scoprire a quale server inviare il pacchetto. A volte i client SSH potrebbero essere in esecuzione su reti in cui l'unico modo per ottenere un indirizzo IPv6 sarebbe utilizzare Teredo. Teredo è noto per essere inaffidabile, ma solo quando la fine IPv6 nativa della connessione utilizza un relay Teredo pubblico. Si può semplicemente mettere un relay Teredo sul gateway, dove si eseguirà il proxy. Miredo può essere installato e configurato come relè in meno di cinque minuti.

Una soluzione alternativa

È possibile utilizzare un host di salto / host bastione. Questo approccio è destinato ai casi in cui non si desidera esporre la porta SSH dei singoli server direttamente a Internet pubblica. Ha il vantaggio aggiuntivo di ridurre il numero di indirizzi IP rivolti verso l'esterno necessari per SSH, motivo per cui è utilizzabile in questo scenario. Il fatto che si tratti di una soluzione destinata ad aggiungere un altro livello di protezione per motivi di sicurezza non impedisce di utilizzarlo quando non è necessaria la sicurezza aggiuntiva.

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

Uno sporco da hackerare per farlo funzionare se la vera soluzione (IPv6) è fuori dalla tua portata

L'hack che sto per descrivere dovrebbe essere usato solo come ultima risorsa. Prima ancora di pensare all'utilizzo di questo hack, consiglio vivamente di ottenere un indirizzo IPv6 per ciascuno dei server che si desidera siano raggiungibili esternamente tramite SSH. Utilizzare IPv6 come metodo principale per accedere ai server SSH e utilizzare questo hack solo quando è necessario eseguire un client SSH da una rete solo IPv4 in cui non si ha alcuna influenza sulla distribuzione di IPv6.

L'idea è che il traffico tra client e server debba essere un traffico SSH perfettamente valido. Ma il proxy deve solo comprendere abbastanza sul flusso di pacchetti per identificare il nome host. Poiché SSH non definisce un modo per inviare un nome host, puoi invece prendere in considerazione altri protocolli che offrono tale possibilità.

HTTP e HTTPS consentono entrambi al client di inviare un nome host prima che il server abbia inviato dati. La domanda ora è se è possibile costruire un flusso di byte che sia contemporaneamente valido come traffico SSH e come HTTP e HTTPS. HTTPs è praticamente un non-principiante, ma HTTP è possibile (per definizioni sufficientemente liberali di HTTP).

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

Ti sembra SSH o HTTP? È SSH e completamente conforme a RFC (tranne per il fatto che alcuni dei caratteri binari sono stati leggermente rovinati dal rendering SF).

La stringa della versione SSH include un campo di commento, che in precedenza ha il valore / HTTP/1.1. Dopo il newline SSH ha alcuni dati di pacchetti binari. Il primo pacchetto è un MSG_SSH_IGNOREmessaggio inviato dal client e ignorato dal server. Il payload da ignorare è:

: 
Host: example.com

Se un proxy HTTP è sufficientemente liberale in ciò che accetta, la stessa sequenza di byte sarebbe interpretata come un metodo HTTP chiamato SSH-2.0-OpenSSH_6.6.1e i dati binari all'inizio del messaggio ignorato sarebbero interpretati come un nome di intestazione HTTP.

Il proxy non comprenderebbe né il metodo HTTP né la prima intestazione. Ma potrebbe capire l' Hostintestazione, che è tutto ciò che serve per trovare il backend.

Affinché ciò funzioni, il proxy dovrebbe essere progettato in base al principio che deve solo comprendere abbastanza HTTP per trovare il back-end e, una volta trovato il back-end, il proxy passerà semplicemente il flusso di byte non elaborato e lascerà la terminazione reale della connessione HTTP che deve essere eseguita dal back-end.

Può sembrare un po 'complicato fare così tante ipotesi sul proxy HTTP. Ma se eri disposto a installare un nuovo software sviluppato con l'intenzione di supportare SSH, i requisiti per il proxy HTTP non sembrano troppo male.

Nel mio caso ho scoperto che questo metodo funziona su un proxy già installato senza modifiche al codice, alla configurazione o altro. E questo era per un proxy scritto con solo HTTP e nessun SSH in mente.

Prova del concetto client e proxy . (Dichiarazione di non responsabilità che il proxy è un servizio gestito da me. Sentiti libero di sostituire il collegamento dopo che è stato confermato qualsiasi altro proxy per supportare questo utilizzo.)

Avvertenze di questo trucco

  • Non usarlo. È meglio usare la soluzione reale, che è IPv6.
  • Se il proxy tenta di comprendere il traffico HTTP, si romperà sicuramente.
  • Affidarsi a un client SSH modificato non è carino.

Puoi elaborare cosa intendi con the gateway can use the destination IP address to find out which server to send the packet tola soluzione IPv6?
Jacob Ford,

@JacobFord La chiave per capire quella frase è che io uso la parola gateway non proxy . Con IPv6 hai abbastanza indirizzi IP per assegnarne uno a ogni host e hai ancora degli indirizzi da risparmiare. Tutte le macchine che avresti messo dietro al proxy avrebbero il loro indirizzo IP che è quello con cui avresti risolto i nomi. Quindi non hai più bisogno di un proxy, i client inviano il loro traffico all'indirizzo IP dell'host desiderato e puoi instradare il traffico direttamente lì.
Kasperd,

per la parte alternativa, c'è un interruttore di comando relativamente nuovo per ssh -J, quindi puoi usare: ssh -J user1 @ front user2 @ target
PMN

3

Non credo che questo sia qualcosa che sarebbe possibile, almeno nel modo in cui hai descritto, anche se mi piacerebbe essere smentito. Non sembra che il client invii il nome host a cui desidera connettersi (almeno in chiaro). Il primo passo della connessione SSH sembra essere l'impostazione della crittografia.

Inoltre, avresti problemi con la verifica della chiave host. I client SSH verificheranno le chiavi in ​​base a un indirizzo IP e un nome host. Avresti più nomi host con chiavi diverse, ma lo stesso IP a cui ti stai connettendo.

Una possibile soluzione sarebbe quella di avere un host "bastion", in cui i client possono accedere a quella macchina, ottenere una shell normale (o limitata se lo si desidera), e da lì può inviare SSH in host interni.


Il concetto di bastione è quello che abbiamo attualmente installato, ma è problematico per il mio controllo della versione (senza ulteriore sforzo).
ahanson,

È davvero fastidioso che ssh non invii il file fqdn e gestisca il DNS sul lato client. Immagino che le persone non si siano preoccupate del gonfio IP pubblico e del NAT quando sono stati creati la maggior parte dei protocolli a livello di applicazione TCP / IP. Perché, sul serio, dovresti essere in grado di eseguire NAT basati su FQDN con iptables (ovvero filtri del kernel).
pregiudizio il

La chiave host potrebbe essere la chiave del proxy inverso. Questo è un vantaggio se ti fidi della sicurezza del backend, poiché hai il controllo della rete interna e degli host.
rox0r,

@bias Non è possibile eseguire NAT in base al nome host, anche se il protocollo di livello superiore invia il nome host. Il motivo per cui non è possibile farlo è che la scelta del backend deve essere fatta quando viene ricevuto il pacchetto SYN, ma il nome host viene inviato solo dopo che il SYN è stato elaborato e un SYN-ACK è stato restituito. Tuttavia, è possibile utilizzare un proxy di livello applicazione molto sottile per i protocolli che inviano il nome host, come http e https.
Kasperd,

3

C'è un nuovo bambino sul blocco. Il piper SSH instraderà la tua connessione in base a nomi utente predefiniti, che dovrebbero essere mappati agli host interni. Questa è la migliore soluzione nel contesto di reverse-proxy.

Pifferaio SSH su github

I miei primi test hanno confermato che SSH e SFTP funzionano entrambi.


Questo è effettivamente un attacco MITM. Mi aspetto che si rompa in ogni installazione protetta dagli attacchi MITM.
Kasperd,

1
In realtà la parte ospitante è sia l'host che l'uomo nel mezzo, quindi solo questi due sono coinvolti.
Király István,

@ KirályIstván questo è un progetto fantastico e prove che altre risposte non sono corrette al 100%. Ho creato uno strumento simile basato su github.com/gliderlabs/sshfront e alcuni bash / python (non riesco ad aprirlo ma non è così interessante - bash esegue client ssh e python è usato come gestore di autenticazione). Ma ho un problema con la soluzione attuale. Non supporta sftp (scp funziona). Si blocca durante il tentativo di eseguire il sottosistema debug1: Sending subsystem: sftp. Si scopre che la parte anteriore della camicia non supporta i sottosistemi. Supportate l'orlo nel piper SSh?
Maciek Sawicki,

1
@MaciekSawicki Non sono l'autore. Lo uso solo nel mio progetto. .)
Király István

2

Mi chiedo se Honeytrap (l'honeypot a bassa interazione) che ha una modalità proxy non possa essere modificato per raggiungere questo obiettivo.

Questo honeypot è in grado di inoltrare qualsiasi protocollo a un altro computer. L'aggiunta di un sistema vhost basato sul nome (come implementato da Apache) potrebbe renderlo un proxy inverso perfetto per qualsiasi protocollo no?

Non ho le competenze per raggiungerlo, ma forse potrebbe essere un grande progetto.


ottima idea!
pregiudizio il

1
La funzione vhost in Apache si basa sul client che invia il nome host prima che i dati siano stati inviati dal server. Il protocollo SSH non prevede un tale nome host, quindi non vedo come inizieresti a implementare una tale funzione. Ma se riesci a elaborare le tue idee, sarei felice di implementare una prova di concetto o dirti, perché non funzionerebbe.
Kasperd,

1

All'aumentare del numero di porte / host a cui si desidera accedere dietro un firewall, aumenta la praticità delle VPN.

Tuttavia, non mi piacciono le VPN.


1

a causa di come funziona ssh penso che non sia possibile. Simile a HTTPS dovresti avere IP (esterni) diversi per host diversi, perché il gateway non sa dove vuoi connetterti perché tutto in ssh è codificato

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.