Trzy rzeczy decydują, którego źródła poświadczeń użyć: czy przy konsoli siedzi człowiek, czy sekret może leżeć na dysku i czy inny proces musi odpowiedzieć na monit. Jeśli wybierzesz źle, klient zgłosi problem ze stdin, choć hasło jest całkowicie poprawne, i to bez powodu wysyła większość ludzi do serwera. Najpierw wybierz ścieżkę; komunikaty o błędach mają sens dopiero wtedy, gdy wiesz, która ścieżka je wywołała.

Trzy warunki, które o tym decydują

Monit konsoli to jedyna ścieżka wymagająca człowieka, więc jedyna, która po cichu zawodzi w unicie systemd lub kontenerze. Jeśli człowiek uruchomi klienta i wpisze hasło, żaden plik nie jest zaangażowany i nic wrażliwego nie trafia na dysk. Jeśli klient startuje przy rozruchu, ten sam monit staje się zawieszeniem, a przekroczenie limitu czasu zwykle pojawia się jako ogólny błąd połączenia, a nie błąd poświadczeń.

Plik poświadczeń jest właściwą odpowiedzią, gdy proces startuje bez nadzoru i sekret może przetrwać na dysku w kontrolowanym zestawie uprawnień. Gdy sekretu nie wolno w ogóle zapisywać - polityka tylko sejfu, krótkotrwały token - potrzebujesz strumienia, który klient może otworzyć, co w praktyce oznacza podstawienie procesu lub pomocnika piszącego do deskryptora pliku. Interfejs zarządzania obejmuje czwarty przypadek: kontroler, który już zarządza cyklem życia tunelu i może odpowiadać na pytania przez gniazdo.

  • Człowiek przy konsoli, brak automatyzacji: monit interaktywny.
  • Start bez nadzoru, sekret można przechowywać: plik poświadczeń w trybie 0600.
  • Start bez nadzoru, sekretu nie można przechowywać: podstawienie procesu lub fd, do którego pisze agent sekretów.
  • Inny proces jest właścicielem klienta: interfejs zarządzania.

Gdy pasują dwie odpowiedzi, wybierz tę, która trzyma sekret poza argv i poza historią powłoki. Hasło przekazane jako argument programu jest czytelne dla każdego lokalnego użytkownika przez listę procesów, a tego ujawnienia trudno cofnąć.

Co naprawdę robi każda ścieżka wejścia

--auth-user-pass sam w sobie pyta o nazwę użytkownika i hasło w konsoli. Gdy dostanie nazwę pliku, klient bierze pierwszy wiersz jako nazwę użytkownika, a drugi jako hasło; nic nie obsługuje cudzysłowów, komentarzy ani składni klucz-wartość. To cały format, więc kto go edytuje, oczekując pliku INI, psuje go. Wbudowany blok <auth-user-pass> zawiera te same dwa wiersze w profilu, co czyni sam profil sekretem i stawia go w tej samej klasie obsługi co klucz prywatny.

Pozostałe dwie ścieżki to strumień i gniazdo. OpenVPN potrzebuje tylko czytelnego deskryptora pliku, więc przyjmie podstawienie procesu, wpis /dev/fd oparty na potoku lub nazwę pliku, która w rzeczywistości jest FIFO. Interfejs zarządzania jest inny z natury: klient pyta nadzorujący proces o wartości, zamiast czytać je sam. Ta różnica ma znaczenie przy ponownym łączeniu: plik poświadczeń, FIFO, do którego pomocnik sekretów może ponownie pisać, oraz interfejs zarządzania mogą dostarczyć ponownie bez człowieka; podstawienie procesu nie może, bo deskryptor zużywa się przy pierwszym odczycie.

Plik musi mieć dokładnie dwa wiersze

Dwa tryby awarii pokrywają większość uszkodzonych plików poświadczeń. Edytor Windows zostawia końce CRLF, powrót karetki staje się częścią hasła, a serwer odrzuca wartość, która na ekranie wygląda poprawnie. Pusty drugi wiersz - pusty wiersz tam, gdzie powinno być hasło - zostawia klienta z pustym hasłem, które serwer odrzuca, choć wartość na ekranie wygląda poprawnie. Dodatkowy znak nowej linii po haśle jest nieszkodliwy. Pisz plik z powłoki, nie z edytora, i sprawdź bajty:

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

Ścieżka jest równie ważna jak zawartość. Ścieżka względna jest rozwiązywana względem katalogu roboczego procesu, który dla usługi rzadko jest katalogiem, w którym testowałeś. Użyj ścieżki bezwzględnej, ustaw plik jako własność konta uruchamiającego klienta i utrzymuj tryb 0600, aby grupa i inni nie mogli go czytać. Podręcznik OpenVPN 2.6 wymienia akceptowane formy dyrektywy; sprawdź go, zanim wymyślisz trzecią.

Przetestuj plik, zanim obwinisz serwer. Uruchomienie openvpn --config client.ovpn --auth-user-pass /etc/openvpn/client.creds --verb 4 wypisuje, czy plik został otwarty i później, czy poświadczenia zostały zaakceptowane, co mówi, którą warstwę zmienić następnie.

Strumienie, stdin i błędy, które produkują

Podanie hasła przez potok to pierwsza rzecz, którą próbuje większość, i ścieżka z największą liczbą niespodzianek. Podstawienie procesu działa, bo klient potrzebuje tylko czytelnego deskryptora: openvpn --config client.ovpn --verb 3 --auth-user-pass <(printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS"). Przekazanie /dev/stdin działa tylko wtedy, gdy stdin jest w chwili pytania wciąż otwarte i czytelne, co nie jest prawdą w potoku, który już je zużył.

ERROR: could not read Auth username from stdin ma dwie różne przyczyny. W niektórych klientach 2.3.x komunikat pochodził z defektu obsługi stdin, który poprawiły późniejsze wydania 2.3, więc tak stary klient poprawia się tylko przez aktualizację. W obecnym kliencie to samo sformułowanie oznacza, że klient poprosił o wejście z konsoli, a stdin nie było terminalem - dokładnie sytuacja w unicie systemd, zadaniu cron lub kontenerze uruchomionym bez -t.

auth-nocache dodaje trzecią pętlę, która wygląda jak zepsute hasło. Wyrzuca poświadczenia z pamięci po użyciu, więc ponowne połączenie wywołane zmianą sieci nie ma czego odtworzyć i monit wraca. To dyrektywa działająca zgodnie z projektem. auth-nocache zmienia to, co klient trzyma w pamięci, a nie to, co serwer lub dostawca tożsamości myśli o koncie, więc cała naprawa to ponowne dostarczenie tego samego pliku, odczytanego ponownie przy restarcie - a dla połączenia zarządzanego to dostarczenie powinno pochodzić z zatwierdzonego magazynu sekretów, nie z hasła w skrypcie.

Interfejs zarządzania, gdy monit należy do innego procesu

Kontroler, który już nadzoruje tunel, może też odpowiadać na jego pytania. Uruchom klienta z --management 127.0.0.1 7505, czytaj wiersze stanu i obserwuj >PASSWORD:Need 'Auth' username/password. Kontroler odpowiada username "Auth" alice, po którym następuje password "Auth" ... w osobnych wierszach poleceń. Token 'Auth' powtarza identyfikator z żądania i musi się zgadzać, inaczej odpowiedź jest ignorowana i klient czeka.

Kosztem jest maszyna stanów, którą teraz posiadasz: kolejność połączeń, restarty klienta i lokalne gniazdo, do którego inni użytkownicy na hoście nie powinni docierać. Kupujesz poświadczenie dostarczane w czasie wykonania, bez pliku na dysku i bez monitu, który może się zawiesić. Jeśli nic innego w twoim stosie nie mówi już tym protokołem, ta ścieżka dodaje komponent do utrzymania.

Awarie, które wyglądają jak problemy z poświadczeniami

Uścisk dłoni TLS, który nigdy się nie kończy, lub VERIFY ERROR: depth=0, error=certificate signature failure, to problem zaufania i dzieje się, zanim zostanie odczytana jakakolwiek nazwa użytkownika. Klient proto tcp skierowany do nasłuchu UDP zawodzi w tym samym miejscu: pakiety nigdy nie docierają do etapu uwierzytelniania, więc każde hasło wygląda na błędne przez skojarzenie. Trzymaj włączoną weryfikację certyfikatów, zanim poświadczenie zostanie wysłane; znajomy monit nic nie mówi o tym, kto otrzymuje hasło. Sprawdź łańcuch certyfikatów, nazwę wspólną i transport, zanim dotkniesz poświadczenia.

Błędy powłoki w skrypcie składającym profil to druga fałszywa ścieżka. Brakująca spacja wewnątrz [ ! -f "$file" ] produkuje command not found, skrypt zatrzymuje się wcześnie, profil nigdy nie jest przebudowywany, a klient startuje z poprzednim. Ten błąd należy do powłoki, nie do uwierzytelniania, i żadne ponowne wpisywanie hasła go nie usunie.

Nie każdy monit w tym przepływie to te poświadczenia. Fraza hasłowa klucza prywatnego, logowanie przez proxy HTTP i hasło usługi to trzy różne sekrety pytane w różnych fazach, a frazą hasłową klucza zwykle zajmuje się klient lub agent, a nie auth-user-pass. Jeśli monit pojawi się, zanim sesja TLS stanie, odpowiadasz na złe pytanie i żaden reset konta nie pomoże. Po wykluczeniu złego monitu pozostałe kontrole zaczynają się od najwcześniejszej warstwy:

  • Czytaj pierwszy błąd protokołu, nie ostatni wiersz poświadczeń: TLS, potem uwierzytelnianie, potem push.
  • Potwierdź, że plik ma dwa wiersze, nie zawiera powrotów karetki i jest wskazany ścieżką bezwzględną.
  • Potwierdź, że profil i wiersz poleceń nie są sprzeczne co do dyrektywy.
  • Oddziel "poświadczenia zaakceptowane" od "ruch płynie" - routing i DNS to późniejsza warstwa.

Gdy klient osiągnie fazę push, przestań patrzeć na poświadczenia i zacznij czytać trasy i serwery DNS wysłane przez serwer. To następny problem i nie ma nic wspólnego z hasłem, które właśnie naprawiłeś.

Powiązane artykuły