Tre cose decidono quale fonte di credenziali usare: se una persona è seduta alla console, se il segreto può vivere sul disco e se un altro processo deve rispondere al prompt. Se scegliete male, il client segnala un problema con stdin mentre la password è perfettamente valida, il che manda la maggior parte delle persone al server senza motivo. Scegliete prima il percorso; i messaggi di errore hanno senso solo quando sapete quale percorso li ha prodotti.

Le tre condizioni che lo decidono

Il prompt della console è l’unico percorso che richiede una persona, quindi è l’unico che fallisce in silenzio in un’unità systemd o in un container. Se una persona avvia il client e digita la password, nessun file è coinvolto e nulla di sensibile finisce sul disco. Se il client parte all’avvio, lo stesso prompt diventa un blocco, e il timeout di solito appare come un guasto di connessione generico invece che come un errore di credenziali.

Un file di credenziali è la risposta giusta quando il processo parte senza supervisione e il segreto può sopravvivere sul disco sotto un insieme di permessi controllato. Quando il segreto non deve essere scritto affatto - una politica solo cassaforte, un token di breve durata - serve un flusso che il client possa aprire, il che in pratica significa sostituzione di processo o un aiutante che scrive in un descrittore di file. L’interfaccia di gestione copre il quarto caso: un controllore che già gestisce il ciclo di vita del tunnel e può rispondere alle domande tramite socket.

  • Persona alla console, nessuna automazione: prompt interattivo.
  • Avvio senza supervisione, il segreto può essere memorizzato: file di credenziali con modo 0600.
  • Avvio senza supervisione, il segreto non può essere memorizzato: sostituzione di processo o un fd scritto da un agente dei segreti.
  • Un altro processo possiede il client: interfaccia di gestione.

Quando due risposte vanno bene, preferite quella che tiene il segreto fuori da argv e fuori dalla cronologia della shell. Una password passata come argomento del programma è leggibile da ogni utente locale tramite la lista dei processi, e quella esposizione è difficile da annullare.

Cosa fa realmente ogni percorso di input

--auth-user-pass da solo chiede un nome utente e una password alla console. Con un nome di file, il client prende la prima riga come nome utente e la seconda come password; nulla supporta virgolette, commenti o sintassi chiave-valore. Questo è tutto il formato, quindi chi lo modifica aspettandosi un file INI lo rompe. Un blocco <auth-user-pass> in linea contiene le stesse due righe nel profilo, il che rende il profilo stesso un segreto e lo colloca nella stessa classe di trattamento di una chiave privata.

Gli altri due percorsi sono un flusso e un socket. OpenVPN ha bisogno solo di un descrittore di file leggibile, quindi accetterà una sostituzione di processo, una voce /dev/fd supportata da una pipe o un nome di file che in realtà è un FIFO. L’interfaccia di gestione è diversa per natura: il client chiede i valori a un processo supervisore invece di leggerli da solo. Questa differenza conta alla riconnessione: un file di credenziali, un FIFO in cui un aiutante dei segreti può riscrivere e l’interfaccia di gestione possono fornire di nuovo senza una persona; la sostituzione di processo no, perché il descrittore viene consumato alla prima lettura.

Il file deve essere esattamente di due righe

Due modalità di guasto coprono la maggior parte dei file di credenziali rotti. Un editor Windows lascia terminazioni CRLF, il ritorno carrello diventa parte della password e il server rifiuta un valore che sullo schermo sembra corretto. Una seconda riga vuota - una riga vuota dove dovrebbe esserci la password - lascia il client con una password vuota, che il server rifiuta anche se il valore sullo schermo sembra corretto. Un a capo finale dopo la password è innocuo. Scrivete il file dalla shell, non da un editor, e controllate i byte:

install -m 600 /dev/null /etc/openvpn/client.creds
printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS" > /etc/openvpn/client.creds
od -c /etc/openvpn/client.creds | head -3

Il percorso conta quanto il contenuto. Un percorso relativo viene risolto rispetto alla directory di lavoro del processo, che per un servizio è raramente la directory in cui avete provato. Usate un percorso assoluto, fate in modo che il file appartenga all’account che esegue il client e mantenete il modo 0600 così che gruppo e altri non possano leggerlo. Il manuale di OpenVPN 2.6 elenca le forme accettate della direttiva; controllatelo prima di inventarne una terza.

Provate il file prima di dare la colpa al server. Eseguire openvpn --config client.ovpn --auth-user-pass /etc/openvpn/client.creds --verb 4 stampa se il file è stato aperto e, più tardi, se le credenziali sono state accettate, il che vi dice quale strato cambiare dopo.

Flussi, stdin e gli errori che producono

Fare passare la password da una pipe è la prima cosa che prova la maggior parte delle persone e il percorso con più sorprese. La sostituzione di processo funziona perché il client ha bisogno solo di un descrittore leggibile: openvpn --config client.ovpn --verb 3 --auth-user-pass <(printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS"). Passare /dev/stdin funziona solo quando stdin è ancora aperto e leggibile nel momento in cui il client chiede, il che non è vero in una pipeline che lo ha già consumato.

ERROR: could not read Auth username from stdin ha due cause distinte. Su alcuni client 2.3.x il messaggio veniva da un difetto di gestione di stdin corretto dalle versioni 2.3 successive, quindi un client così vecchio migliora solo aggiornandosi. Su un client attuale la stessa formulazione significa che il client ha chiesto input da console e che stdin non era un terminale - esattamente la situazione in un’unità systemd, in un’attività cron o in un container avviato senza -t.

auth-nocache aggiunge un terzo ciclo che sembra una password rotta. Scarta le credenziali dalla memoria dopo l’uso, quindi una riconnessione causata da un cambio di rete non ha nulla da riprodurre e il prompt ritorna. È la direttiva che funziona come progettata. auth-nocache cambia ciò che il client tiene in memoria, non ciò che il server o il provider di identità pensa dell’account, quindi tutta la correzione è fornire di nuovo lo stesso file, riletto al riavvio - e per una connessione gestita quella fornitura dovrebbe venire dall’archivio dei segreti approvato, non da una password in uno script.

L’interfaccia di gestione quando un altro processo possiede il prompt

Un controllore che già sorveglia il tunnel può anche rispondere alle sue domande. Avviate il client con --management 127.0.0.1 7505, leggete le righe di stato e tenete d’occhio >PASSWORD:Need 'Auth' username/password. Il controllore risponde con username "Auth" alice seguito da password "Auth" ... su righe di comando separate. Il token 'Auth' ripete l’identificatore della richiesta e deve corrispondere, altrimenti la risposta viene ignorata e il client attende.

Il costo è una macchina a stati che ora possedete: ordine delle connessioni, riavvii del client e un socket locale che gli altri utenti dell’host non devono raggiungere. Ciò che comprate è una credenziale fornita a runtime, senza file sul disco e senza un prompt che possa bloccarsi. Se nient’altro nel vostro stack parla già il protocollo, questo percorso aggiunge un componente da mantenere.

Guasti che sembrano problemi di credenziali

Una stretta di mano TLS che non si completa mai, o un VERIFY ERROR: depth=0, error=certificate signature failure, è un problema di fiducia e avviene prima che venga letto qualsiasi nome utente. Un client proto tcp puntato a un listener UDP fallisce nello stesso punto: i pacchetti non raggiungono mai la fase di autenticazione, quindi ogni password sembra sbagliata per associazione. Tenete attiva la verifica dei certificati prima che la credenziale venga inviata; un prompt familiare non dice nulla su chi riceve la password. Controllate la catena dei certificati, il nome comune e il trasporto prima di toccare la credenziale.

I bug della shell nello script che assembla il profilo sono l’altra falsa pista. Uno spazio mancante dentro [ ! -f "$file" ] produce command not found, lo script si ferma prima, il profilo non viene mai ricostruito e il client parte con quello precedente. Quell’errore appartiene alla shell, non all’autenticazione, e nessuna riscrittura della password lo cancellerà.

Non ogni prompt in questo flusso è questa credenziale. Una passphrase di chiave privata, un accesso proxy HTTP e la password del servizio sono tre segreti diversi richiesti in fasi diverse, e una passphrase di chiave è di solito gestita dal client o da un agente invece che da auth-user-pass. Se il prompt appare prima che la sessione TLS sia attiva, state rispondendo alla domanda sbagliata e nessun reset dell’account aiuterà. Una volta escluso il prompt sbagliato, i controlli rimanenti partono dallo strato più precoce:

  • Leggete il primo errore di protocollo, non l’ultima riga di credenziali: TLS, poi autenticazione, poi push.
  • Confermate che il file è di due righe, non contiene ritorni carrello ed è referenziato con un percorso assoluto.
  • Confermate che il profilo e la riga di comando non sono in disaccordo sulla direttiva.
  • Separate "credenziali accettate" da "il traffico scorre" - instradamento e DNS sono uno strato successivo.

Quando il client raggiunge la fase push, smettete di guardare le credenziali e iniziate a leggere le route e i server DNS inviati dal server. Questo è il problema successivo, e non ha nulla a che fare con la password che avete appena corretto.

Articoli correlati