Aplikacja uwierzytelniająca pokazuje nowy sześciocyfrowy kod, VPN go odrzuca, a ten sam kod weryfikuje się bezbłędnie, gdy testujesz go z własnej powłoki. Ta różnica to cała historia. Moduł PAM, który nie może otworzyć sekretu rejestracji, zwraca błąd wyglądający identycznie jak zły kod, a środowisko usługi ukrywające katalogi domowe jest częstą przyczyną. Zanim poluzujesz jakiekolwiek uprawnienie, zdecyduj, w której z trzech sytuacji się znajdujesz.

Która z trzech awarii to jest?

Pierwsza to sekret, którego moduł w ogóle nie może odczytać. Druga to sekret, który może odczytać, ale nie zaktualizować. Trzecia to kod, który naprawdę jest błędny, zwykle z powodu dryfu zegara lub ponownie użytej wartości.

Rozdziel je, czytając dziennik usługi i dziennik uwierzytelniania systemu dla jednej nieudanej próby, a następnie potwierdź, którą usługę PAM ładuje wtyczka i której linii modułu używa ta usługa. Ogólny komunikat błędu uwierzytelniania ich nie rozróżnia, podobnie jak udany test ręczny, ponieważ twoja powłoka nie jest środowiskiem usługi.

Widok systemu plików jednostki jest zwykłym winowajcą, gdy zawodzi tylko usługa.

systemctl show -p ProtectHome -p ProtectSystem -p ReadWritePaths [email protected]
ls -l /var/lib/vpn-otp/*/.google_authenticator 2>/dev/null | head -n 20

Opcja A: przenieś sekret poza katalog domowy

Gdy usługa ukrywa /home, a ty wolisz zachować tę ochronę, przechowuj sekret tam, gdzie może go zobaczyć. Moduł akceptuje ścieżkę secret= i konto user=, które wykonuje operacje na plikach, co pozwala centralnemu magazynowi obsługiwać wiele tożsamości.

To schludna opcja i wymaga najwięcej staranności, ponieważ wspólny magazyn czyni jeden katalog granicą bezpieczeństwa każdego konta.

auth required pam_google_authenticator.so secret=/var/lib/vpn-otp/${USER}/.google_authenticator user=vpn-otp

Sprawdź trzy rzeczy, zanim jej zaufasz: konto istnieje, proces roboczy modułu może się na nie przełączyć, a pliki należą do niego z restrykcyjnymi uprawnieniami. Nie używaj ~ ani ścieżki ze zmienną domową razem z user= i nie wyłączaj kontroli własności modułu, aby ścieżka zadziałała. Zachowaj etap hasła i resztę stosu nietknięte.

Opcja B: zostaw plik i otwórz ścieżkę

Jeśli sekret musi pozostać w katalogu domowym użytkownika, jednostka potrzebuje widoku obejmującego ten jeden katalog bez ujawniania wszystkich katalogów domowych na hoście. Drop-in może dodać wąsko ograniczony bind mount pod katalogiem domowym w sandboksie.

To zachowuje własność per użytkownik jako model, kosztem zmiany jednostki, którą trzeba przeglądać za każdym razem, gdy zmienia się sandbox.

Dwie granice łatwo przeoczyć. Ścieżka tylko do odczytu dodana pod katalogiem, który sandbox ukrywa, nie ujawnia go, ponieważ katalog nadrzędny po prostu nie istnieje. A montowanie musi być zapisywalne, jeśli moduł ma aktualizować stan, co wprowadza kolejną opcję. Zapisz drop-in jako osobny plik, zamiast edytować spakowaną jednostkę pod /usr/lib, aby aktualizacja pakietu nie cofnęła go po cichu.

Opcja C: zachowaj sandbox i napraw zapisy stanu

Odczyt sekretu to tylko połowa uwierzytelniania. Moduł może przepisywać informacje o odchyleniu czasu, ochronę przed powtórzeniem lub licznik, a plik, który przejdzie kontrolę odczytu, nadal może zawieść przy zapisie.

Ta awaria wygląda jak zły kod przy następnej próbie, a nie przy tej, dlatego myli się ją z dryfem zegara.

Daj mu własny zapisywalny katalog i skieruj tam ścieżkę sekretu, zamiast czynić zapisywalnym cały katalog domowy. Potwierdź właściciela katalogu, wolne miejsce w systemie plików i to, czy jednostka ogranicza zapisy gdzie indziej. Następnie przetestuj dwa kolejne logowania, ponieważ drugie dowodzi ścieżki zapisu, a pierwsze tylko odczytu.

Weryfikuj jako usługa, a nie jako ty sam

Każda istotna kontrola musi działać w sandboksie jednostki z tożsamością jednostki.

Polecenie, które kończy się sukcesem jako root, mówi ci, że plik istnieje, i nic więcej. Logowanie przez rzeczywistą usługę mówi ci, czy moduł może odczytać sekret, użyć go i zapisać z powrotem to, czego potrzebuje.

Na koniec zachowaj wymóg nietknięty. Dodanie opcji pustego hasła, akceptowanie awarii tylko do odczytu lub usunięcie sandboxa usunęłyby objaw przez zmianę polityki. Użytkownik zobowiązany do przedstawienia kodu nadal powinien być odrzucany, gdy sekret jest nieosiągalny.

Powiązane artykuły