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_IGNORE
messaggio 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.1
e 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' Host
intestazione, 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.