Implementazione del Port Forwarding SSH Locale e Remoto per il Tunneling
Sblocca l'accesso sicuro alla rete e il superamento dei firewall utilizzando il port forwarding SSH. Questa guida completa illustra l'implementazione pratica delle tecniche di tunneling SSH sia Locale (`-L`) che Remoto (`-R`). Impara la sintassi essenziale, comprendi le differenze chiave tra l'accesso a servizi remoti e l'esposizione di servizi locali, e vedi esempi chiari per attività come la protezione delle connessioni al database o la condivisione di ambienti di sviluppo. Include le migliori pratiche critiche per creare tunnel in background persistenti e sicuri utilizzando l'autenticazione basata su chiave.
Implementazione del Port Forwarding SSH Locale e Remoto per il Tunneling
Il port forwarding SSH è uno di quegli strumenti di cui ti dimentichi finché un firewall, una sottorete privata o una rete aziendale scomoda non bloccano il percorso semplice. Poi diventa la soluzione più rapida e pulita. Puoi usarlo per raggiungere un database attraverso un host bastione, testare una pagina di amministrazione privata dal tuo laptop o esporre un server di sviluppo locale a una macchina che non può raggiungere direttamente il tuo laptop.
L'idea di base è semplice: SSH apre una porta in ascolto su un lato della connessione e trasporta il traffico attraverso la sessione SSH crittografata verso una destinazione sull'altro lato. La parte che crea confusione è la direzione. Il forwarding locale con -L permette alla tua macchina di raggiungere qualcosa vicino al server SSH. Il forwarding remoto con -R permette a qualcosa vicino al server SSH di raggiungere qualcosa vicino alla tua macchina.
Forwarding locale: porta un servizio remoto sul tuo laptop
Usa il forwarding locale quando il servizio di cui hai bisogno è raggiungibile dal server SSH, ma non dalla tua workstation.
ssh -L 15432:db.internal.example:5432 [email protected]
Dopo che questo si connette, il tuo laptop ascolta su 127.0.0.1:15432. Quando punti psql, DBeaver o una configurazione dell'applicazione verso quella porta locale, SSH invia il traffico a bastion.example.com, e il bastione apre una connessione a db.internal.example:5432.
Leggi il comando da sinistra a destra:
porta locale sulla mia macchina : host di destinazione come visto dal server SSH : porta di destinazione
Quel "come visto dal server SSH" è un dettaglio importante. Se il database si chiama db.internal.example solo all'interno della rete privata, il tuo laptop non deve risolvere quel nome. Lo fa il bastione. Se il database ascolta solo su localhost sul bastione, usa invece questo:
ssh -L 15432:127.0.0.1:5432 [email protected]
Il forwarding locale è di solito l'impostazione predefinita più sicura perché la porta in ascolto è sulla tua workstation. Di default, OpenSSH vincola le porte inoltrate localmente all'interfaccia di loopback, quindi altre macchine sulla tua Wi-Fi o rete aziendale non possono usare il tunnel. Puoi essere esplicito:
ssh -L 127.0.0.1:15432:db.internal.example:5432 [email protected]
Evita di vincolare a 0.0.0.0 a meno che tu non voglia davvero condividere il tunnel con altri host. Un comando come questo trasforma il tuo laptop in un proxy per il database privato per chiunque possa raggiungere la porta 15432 sul tuo laptop:
ssh -L 0.0.0.0:15432:db.internal.example:5432 [email protected]
Potrebbe essere utile in un laboratorio. Raramente è ciò che vuoi su una workstation normale.
Forwarding remoto: espone un servizio locale attraverso il server
Il forwarding remoto inverte il lato in ascolto. Usalo quando un servizio è in esecuzione sulla tua macchina, ma qualcuno o qualcosa vicino al server SSH deve raggiungerlo.
ssh -R 18080:127.0.0.1:3000 [email protected]
Questo chiede a public.example.com di mettersi in ascolto sulla porta 18080. Le connessioni a quella porta vengono riportate indietro attraverso SSH a 127.0.0.1:3000 sul tuo laptop. Questo è utile quando stai testando un ricevitore di webhook, condividendo una demo temporanea o eseguendo il debug di un callback da un sistema di staging che non può chiamare direttamente il tuo laptop.
C'è una sorpresa comune: le porte inoltrate in remoto di solito si legano al loopback sul server SSH per impostazione predefinita. Ciò significa che curl http://127.0.0.1:18080 funziona se eseguito su public.example.com, ma http://public.example.com:18080 dal tuo browser potrebbe non funzionare.
Per rendere una porta inoltrata in remoto raggiungibile da altre macchine, il server SSH deve permetterlo. In /etc/ssh/sshd_config, l'impostazione rilevante è comunemente:
GatewayPorts clientspecified
Quindi puoi richiedere un bind pubblico:
ssh -R 0.0.0.0:18080:127.0.0.1:3000 [email protected]
Usalo con cautela. Stai pubblicando un servizio locale attraverso il server. Metti un firewall davanti, usa una porta alta casuale e non esporre strumenti di amministrazione, database di sviluppo o app non autenticate a Internet.
Mantieni i tunnel noiosi e affidabili
Per un tunnel di lunga durata, di solito non vuoi una shell sull'host remoto:
ssh -N -L 15432:db.internal.example:5432 [email protected]
-N significa "non eseguire un comando remoto." Aggiungi keepalive quando il tunnel attraversa NAT, VPN o bilanciatori di carico cloud che interrompono le sessioni TCP inattive:
ssh -N \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-L 15432:db.internal.example:5432 \
[email protected]
Per uso non presidiato, preferisci un servizio systemd utente, autossh o il tuo supervisore di processo rispetto a un comando ssh -f nudo. L'esecuzione in background con -f funziona, ma rende più difficile notare avvii falliti e tunnel obsoleti.
ssh -fN -L 15432:db.internal.example:5432 [email protected]
Se usi -fN, testa prima lo stesso comando senza -f. I prompt per la password, i prompt per la chiave host sconosciuta e i conflitti di porta sono molto più facili da diagnosticare in primo piano.
Checklist per la risoluzione dei problemi
Quando un tunnel si connette ma l'applicazione fallisce ancora, controlla ogni hop invece di indovinare.
Prima, conferma che il listener locale esista:
ss -ltnp | grep 15432
Poi testa la destinazione dal server SSH:
ssh [email protected] 'nc -vz db.internal.example 5432'
Se questo fallisce, il forwarding SSH non è il problema. Il bastione non può raggiungere il servizio, il nome non viene risolto lì, un gruppo di sicurezza blocca la porta o il servizio è vincolato all'interfaccia sbagliata.
Se il listener non si avvia, la porta locale potrebbe essere già in uso:
lsof -iTCP:15432 -sTCP:LISTEN
Se il forwarding remoto fallisce con un messaggio come remote port forwarding failed, il server potrebbe bloccare il forwarding TCP. Controlla AllowTcpForwarding in sshd_config e verifica se la porta richiesta è già occupata.
Abitudini di sicurezza che vale la pena mantenere
Usa l'autenticazione basata su chiave e limita l'account utilizzato per i tunnel. Per un utente tunnel dedicato, puoi combinare accesso shell limitato, regole firewall e opzioni SSH come PermitOpen o PermitListen a seconda della direzione di cui hai bisogno. Questi controlli impediscono a un tunnel di comodità di trasformarsi in un accesso di rete esteso.
Nomina i tunnel nelle tue note o runbook per intento, non solo per comando. "Laptop 15432 per replica di reportistica di produzione attraverso bastione" è più facile da controllare rispetto a una misteriosa riga ssh -L nella cronologia della shell.
Il forwarding locale ti aiuta a raggiungere l'interno. Il forwarding remoto permette ad altri di raggiungerti. Una volta chiara questa distinzione, la maggior parte dei problemi di tunneling SSH diventa una questione di controllare quale lato ascolta, quale lato risolve la destinazione e quale firewall si trova tra di loro.
Alcuni schemi reali che vedrai
Uno schema comune in produzione è il tunnel di manutenzione del database. Hai una replica di reportistica in una sottorete privata, un host bastione con accesso SSH rigoroso e uno strumento di analisi sul tuo laptop. Il forwarding locale si adatta perfettamente:
ssh -N -L 127.0.0.1:15432:reporting-db.internal:5432 [email protected]
L'applicazione sul tuo laptop dovrebbe usare 127.0.0.1, non il nome host del database privato. Se lo strumento insiste sulla verifica del nome host SSL rispetto all'host del database, potresti doverti connettere con il nome host del database e aggiungere una voce hosts locale, o configurare il client con la modalità SSL corretta. Il tunnel sposta solo byte TCP; non riscrive i dettagli del protocollo del database.
Un altro schema è un ricevitore di webhook temporaneo:
ssh -N -R 127.0.0.1:19090:127.0.0.1:9090 [email protected]
In questa versione, la porta inoltrata è intenzionalmente utilizzabile solo dal gateway stesso. Potresti quindi configurare un servizio di staging sul gateway per chiamare http://127.0.0.1:19090/hook. Questo è più sicuro che pubblicare la porta su tutta la rete.
Per una demo pubblica breve, usa un bind pubblico solo dopo aver aggiunto una regola firewall:
ssh -N -R 0.0.0.0:19090:127.0.0.1:3000 [email protected]
Quindi limita il gateway:
sudo ufw allow from 203.0.113.40 to any port 19090 proto tcp
Senza questa restrizione, chiunque possa raggiungere il gateway può provare il servizio inoltrato.
Cosa non risolve il tunneling SSH
Il forwarding SSH non sostituisce l'autenticazione del servizio. Se il database accetta connessioni locali senza password, un tunnel potrebbe estendere quel confine di fiducia debole più del previsto. Se un'app di sviluppo locale non ha una pagina di login, il forwarding remoto può pubblicarla così com'è.
Inoltre non rende affidabile una destinazione instabile. Se il bastione non può risolvere il nome interno, se il servizio è giù o se un gruppo di sicurezza blocca il percorso, il tunnel può comunque stabilirsi con successo mentre l'applicazione fallisce. Ecco perché testare dal server SSH è così utile.
Infine, i tunnel sono facili da dimenticare. Un tunnel obsoleto su un host di salto condiviso può lasciare una porta inaspettata aperta. Per qualsiasi cosa di lunga durata, metti il comando in un file di servizio con un nome chiaro, proprietario e politica di riavvio. Per qualsiasi cosa temporanea, chiudilo quando il lavoro è finito e verifica che il listener sia scomparso con ss -ltnp.