Raggiungere un’interfaccia web dentro un contenitore VPN: scegliete il proprietario della porta
L’app condivide lo spazio dei nomi della VPN, quindi la porta appartiene al contenitore VPN. Collegate l’ascoltatore correttamente, pubblicate sul proprietario e mantenete stretto il percorso.
Non c’è niente di sbagliato nell’app né niente di sbagliato nel tunnel, eppure la dashboard non si carica. Quando un servizio gira con network_mode: service:vpn, condivide lo spazio dei nomi di rete del contenitore VPN, il che significa che il suo ascoltatore e le sue porte pubblicate appartengono a quello spazio dei nomi e non al servizio. Da ciò derivano tre decisioni: dove si lega l’app, quale contenitore pubblica la porta e quanto è stretto il percorso di gestione. Mettetele nell’ordine sbagliato e ogni singola impostazione sembrerà corretta mentre la combinazione non può funzionare.
Chi possiede lo spazio dei nomi della porta
In uno spazio dei nomi condiviso, aggiungere una voce ports: al servizio dipendente non serve a nulla, e diverse opzioni di rete non sono supportate per esso per progettazione. Pubblicate invece sul contenitore che possiede lo spazio dei nomi. Quel contenitore è anche quello il cui indirizzo compare sull’host, quindi la mappatura si legge come una voce sola e non una per servizio.
services:
vpn:
image: vpn-client-image
cap_add: [NET_ADMIN]
ports:
- "127.0.0.1:8080:8080"
app:
network_mode: "service:vpn"
Notate l’indirizzo a sinistra della mappatura. Il binding a 127.0.0.1 tiene la porta pubblicata sul loopback dell’host, che di solito è ciò che vuole un’interfaccia di gestione. Il binding a 0.0.0.0 la espone su ogni interfaccia dell’host, e questa è una decisione di sicurezza diversa, non una comodità.
Fate ascoltare l’app dove lo spazio dei nomi se lo aspetta
Un ascoltatore legato a 127.0.0.1 dentro lo spazio dei nomi è raggiungibile solo dall’interno di quello spazio. Le porte pubblicate dell’host arrivano da fuori, quindi l’app deve legare un indirizzo più ampio perché la mappatura funzioni. È una modifica di una riga nella maggior parte dei server, ed è esattamente il passo che si salta dopo aver copiato una guida di hardening scritta per un deployment senza contenitori.
docker compose exec app ss -lntp
docker port vpn
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/
L’elenco degli ascoltatori dentro l’app dice la verità sull’indirizzo di bind, e docker port dice cosa ha pubblicato davvero il proprietario. Se il primo mostra 127.0.0.1 e il secondo mostra una mappatura sull’host, avete trovato la discrepanza senza toccare la configurazione della VPN.
Scegliete come entra il percorso di gestione
Ci sono tre disposizioni ragionevoli. Pubblicate sul contenitore VPN e raggiungetelo dall’host o dalla rete locale. Mettete un proxy inverso davanti allo spazio dei nomi e date al proxy l’unica porta esposta. Oppure mantenete la dashboard raggiungibile solo dall’interno dello spazio dei nomi tramite una sessione exec o un tunnel SSH, che è la minore esposizione e la minore comodità.
Quale si adatta dipende da chi ha bisogno dell’interfaccia e da dove. Un singolo amministratore sullo stesso host si accontenta di un binding loopback. Un team che vi accede tramite la VPN ha bisogno di un percorso ponderato e di un proprietario nominato. Scegliere l’opzione proxy vi dà TLS e log di accesso, al prezzo di un altro componente da tenere aggiornato.
Aprite la porta di gestione senza aprire tutto
La politica di accesso locale o di blocco del client VPN può scartare una richiesta di gestione in ingresso anche mentre il tunnel in uscita funziona perfettamente. Consentite un’eccezione documentata per l’origine e la porta previste, poi confermate che la protezione ordinaria del tunnel è invariata. Disattivare il kill switch per far caricare una dashboard scambia un controllo reale con una scheda del browser.
Lasciate attiva l’autenticazione propria dell’app. Trovarsi dentro uno stack connesso alla VPN non autorizza ogni utente locale né ogni dispositivo che può raggiungere l’host, e un pannello di amministrazione senza autenticazione dietro un tunnel resta un pannello di amministrazione senza autenticazione.
Verificate dal dispositivo di gestione, poi verificate di nuovo più tardi
Provate dalla macchina che gestirà davvero il servizio, non dall’host, poi verificate separatamente il percorso internet richiesto dall’app. Un successo di gestione dimostra una direzione e non dice nulla sull’uscita.
Riprovate dopo che lo stack è stato ricreato. Un proprietario di rete sostituito cambia lo spazio dei nomi a cui l’app si aggancia, e un URL che funzionava prima di un aggiornamento può dopo non puntare a nulla. Annotate la mappatura pubblicata e l’indirizzo di bind così che la prossima ricostruzione sia una verifica di due minuti invece di un’indagine ripetuta.