SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor

SSH: „Too many authentication failures” – naprawa

Błąd „Too many authentication failures” pojawia się po przekroczeniu domyślnego limitu 6 prób. Sprawdź ofertę kluczy poleceniem ssh -v i ogranicz ją do właściwego.

Co oznacza komunikat "Too many authentication failures"

Komunikat "Too many authentication failures" oznacza, że klient SSH zaoferował serwerowi więcej kluczy, niż ten był w stanie sprawdzić, przez co serwer zamknął połączenie przed próbą użycia właściwego klucza. Jest to niemal zawsze problem po stronie klienta. Klucz znajduje się na dysku, serwer posiada go w authorized_keys, jednak te fakty nie mają znaczenia, ponieważ połączenie zostało przerwane zbyt wcześnie.

Oto mechanizm tego zjawiska. ssh-agent przechowuje wszystkie klucze prywatne, które zostały do niego załadowane. Klient oferuje te klucze serwerowi pojedynczo, ponieważ nie posiada informacji, który z nich jest akceptowany przez konto. Serwer odrzuca każdy klucz, którego nie ma w authorized_keys, i zlicza każde odrzucenie jako nieudaną próbę uwierzytelnienia. Parametr MaxAuthTries w pliku sshd_config ogranicza liczbę dozwolonych niepowodzeń w ramach jednego połączenia. Wartość domyślna wynosi 6. Jeśli agent przechowuje dziesięć kluczy, a właściwy znajduje się na ósmej pozycji, serwer rozłączy sesję, zanim do niego dotrze.

Rozwiązaniem jest skonfigurowanie klienta tak, aby oferował tylko jeden, właściwy klucz.

Co serwer zlicza i gdzie pojawia się MaxAuthTries

Uwierzytelnianie za pomocą klucza publicznego zaczyna się od sprawdzania kolejnych możliwości. Klient wysyła klucz publiczny i pyta, czy serwer zaakceptuje podpis wykonany za jego pomocą. Serwer odpowiada twierdząco albo przecząco. Odpowiedź przecząca oznacza nieudaną próbę, dokładnie tak samo jak nieprawidłowe hasło.

Strona podręcznika sshd_config(5) opisuje ten limit: „Określa maksymalną liczbę prób uwierzytelnienia dozwolonych w ramach jednego połączenia. Po osiągnięciu połowy tej wartości kolejne nieudane próby są zapisywane w dzienniku. Wartość domyślna wynosi 6”.

Sześć prób wystarcza osobie wpisującej hasło. To niewiele w przypadku agenta mającego dziesięć kluczy. Po osiągnięciu limitu nieudanych prób sshd rozłącza klienta i zapisuje w dzienniku systemowym wpis podobny do tego:

error: maximum authentication attempts exceeded for deploy from 203.0.113.10 port 51292 ssh2

Klient wyświetla drugą część tego samego zdarzenia:

Received disconnect from 203.0.113.10 port 22:2: Too many authentication failures
Disconnected from 203.0.113.10 port 22

Jest to inny błąd niż błąd SSH permission denied (publickey). W tamtej sytuacji serwer sprawdził wszystkie przedstawione klucze i nie zaakceptował żadnego z nich. Tutaj serwer przestał je sprawdzać. Traktowanie tych błędów jako tego samego problemu prowadzi do wielokrotnego kopiowania klucza, który już był prawidłowy.

Dlaczego ten sam klucz działa z laptopa współpracownika

Klucz oraz serwer nie różnią się niczym. Agent współpracownika przechowuje dwa klucze, a Twój dwanaście. Oferta, która dla nich dociera jako pierwsza, dla Ciebie jest dziewiąta w kolejności, a do tego czasu połączenie zostaje zakończone.

Liczba kluczy rośnie niezauważenie. AddKeysToAgent yes w ~/.ssh/config dodaje każdy użyty klucz do agenta i pozostawia go tam. Agenty pęku kluczy w środowiskach graficznych, takie jak GNOME Keyring w systemie Linux lub login keychain w systemie macOS, ładują klucze podczas logowania bez pytania. Dodanie klucza klienta, klucza hosta git oraz klucza do serwera laboratoryjnego w ciągu roku sprawia, że pewnego dnia serwer, który zawsze działał, zaczyna odmawiać dostępu. Na serwerze nic się nie zmieniło. Twój agent stał się zbyt pełny.

Jak sprawdzić oferty za pomocą ssh -v

Uruchom nieudane połączenie z flagą -v i przeanalizuj ślad.

ssh -v deploy@203.0.113.10

Istotne są dwa rodzaje linii. Will attempt key: wymienia tożsamości zebrane przez klienta w kolejności, w jakiej zostaną użyte. Offering public key: pojawia się raz dla każdego klucza faktycznie wysłanego do serwera.

debug1: Will attempt key: /home/you/.ssh/id_ed25519 ED25519 SHA256:AAAA... agent
debug1: Will attempt key: /home/you/.ssh/id_rsa RSA SHA256:BBBB... agent
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:AAAA... agent
debug1: Authentications that can continue: publickey,password
debug1: Offering public key: /home/you/.ssh/id_rsa RSA SHA256:BBBB... agent

Ścieżki, typy kluczy oraz odciski palców będą się różnić. Należy policzyć liczbę linii Offering public key: przed rozłączeniem. Jeśli oferty przewijają się, a sesja kończy się bez pojawienia się oczekiwanego klucza, diagnoza jest ustalona. Słowo agent na końcu linii oznacza, że tożsamość pochodzi z ssh-agent. Słowo explicit oznacza, że pochodzi ona z linii IdentityFile lub z -i w wierszu poleceń.

Następnie sprawdź, jakie klucze przechowuje agent:

ssh-add -l

Każda linia wyjścia to jeden załadowany klucz. Jeśli wyświetlony zostanie komunikat The agent has no identities., problem nie leży po stronie agenta i należy sprawdzić linie IdentityFile w pliku ~/.ssh/config. Jeśli wyświetlony zostanie komunikat Could not open a connection to your authentication agent., oznacza to, że agent nie jest uruchomiony, a oferty pochodzą z domyślnych plików kluczy.

Sposób 1: IdentitiesOnly z jednym kluczem na hosta

IdentitiesOnly yes powoduje, że ssh oferuje tylko skonfigurowane tożsamości i ignoruje dodatkowe tożsamości udostępniane przez agenta. W połączeniu z wpisem IdentityFile klient wysyła tylko jedną ofertę.

Host vps
  HostName 203.0.113.10
  User deploy
  IdentityFile ~/.ssh/id_ed25519_vps
  IdentitiesOnly yes

Zapisz konfigurację w ~/.ssh/config, a następnie uruchom chmod 600 ~/.ssh/config. Plik zapisywalny przez grupę lub wszystkich użytkowników powoduje odmowę uruchomienia ssh z komunikatem Bad owner or permissions on /home/you/.ssh/config. Polecenie ssh vps oferuje wtedy jeden klucz, a ssh -v vps powinno wyświetlić dokładnie jeden wiersz Offering public key:.

Warto zwrócić uwagę na dwie kwestie.

  • Sam wpis IdentitiesOnly yes nie oznacza „jeden klucz”. Jeśli nie ma wiersza IdentityFile, domyślne pliki tożsamości są traktowane jako skonfigurowane tożsamości, dlatego ssh nadal próbuje użyć ~/.ssh/id_ed25519, ~/.ssh/id_rsa oraz innych znalezionych plików domyślnych. Potrzebny jest również wpis IdentityFile: po jego ustawieniu ssh przestaje dodawać domyślne tożsamości.
  • Agent nadal wykonuje podpisywanie. IdentitiesOnly określa, które klucze są oferowane, a nie to, kto je podpisuje. Jeśli klucz prywatny wskazany przez IdentityFile jest załadowany w agencie, agent tworzy podpis i hasło nie jest żądane. Można nawet wskazać w IdentityFile pasujący plik .pub. Stosuje się to, gdy klucz prywatny znajduje się wyłącznie w agencie lub na tokenie sprzętowym.

Jeden szczegół w ~/.ssh/config może po cichu unieważnić tę poprawkę. W przypadku większości słów kluczowych używana jest pierwsza znaleziona wartość, dlatego szczegółowe bloki Host powinny znajdować się przed Host *. IdentityFile nie działa według tej zasady. W podręczniku opisano to następująco: „W plikach konfiguracyjnych można określić wiele plików tożsamości; wszystkie te tożsamości będą sprawdzane po kolei”. Wpis IdentityFile w sekcji Host * zostaje dodany do wpisu dotyczącego konkretnego hosta, a nie zastępuje go. Zapomniany wpis globalny ponownie dodaje dodatkową ofertę do każdego połączenia.

Aby ustawić globalne zabezpieczenie, umieść na końcu pliku wyłącznie tę flagę:

Host *
  IdentitiesOnly yes

Każdy host musi wtedy mieć własny wpis IdentityFile. Jest to pożądany rezultat. Nazwanie jednego klucza dla każdego serwera umożliwia również późniejsze odebranie dostępu pojedynczej maszynie bez ponownego wydawania wszystkich kluczy. Warto wyrobić ten nawyk od początku: zobacz jak zarządzać kluczami SSH dla poszczególnych maszyn.

Rozwiązanie 2: wyczyszczenie lub restart agenta

Jeśli edycja konfiguracji nie jest jeszcze możliwa, należy opróżnić agenta i załadować tylko niezbędne elementy.

ssh-add -l                    # list what is loaded
ssh-add -d ~/.ssh/id_rsa      # remove one key
ssh-add -D                    # remove every key
ssh-add ~/.ssh/id_ed25519_vps # load the one you need

Jeśli połączenie działa poprawnie bezpośrednio po wykonaniu ssh-add -D, przyczyną był agent. Należy traktować to jako test, a nie naprawę. Agent pęku kluczy środowiska graficznego przeładowuje klucze przy następnym logowaniu, więc problem powróci kolejnego dnia. Wpis IdentitiesOnly w pliku ~/.ssh/config przetrwa restart systemu. Pusty agent nie.

Można również nadać kluczowi czas życia, aby agent automatycznie go usunął:

ssh-add -t 1800 ~/.ssh/id_ed25519_vps

Klucz zostanie usunięty 1800 sekund po dodaniu. Restart agenta również jest skuteczny, a sposób jego wykonania zależy od metody uruchomienia. Proces ssh-agent uruchomiony samodzielnie zatrzymuje się za pomocą ssh-agent -k. W przypadku jednostki użytkownika systemd, należy zrestartować ją poleceniem systemctl --user restart <unit>. Agent pęku kluczy restartuje się wraz z sesją użytkownika.

Poprawka 3: polecenie jednorazowe dla serwera, z którym łączysz się sporadycznie

W przypadku hosta, którego nie chcesz dodawać do konfiguracji, umieść te same ustawienia w wierszu poleceń:

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10

Samo -i jest najczęstszą błędną poprawką. -i dodaje klucz do listy tożsamości. Nie usuwa ono kluczy agenta z tej listy, więc wszystkie inne oferty nadal są wysyłane przed Twoją, a połączenie nadal zostaje zerwane po osiągnięciu limitu. Uruchom ssh -v -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10 bez IdentitiesOnly, a zobaczysz, że klucze agenta są oferowane jako pierwsze. -i wymaga obecności -o IdentitiesOnly=yes.

Aby całkowicie wykluczyć agenta z procesu dla pojedynczego połączenia:

ssh -o IdentityAgent=none -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10

ssh odczytuje wtedy klucz prywatny z dysku i prosi o hasło, jeśli zostało ono ustawione.

Narzędzia oparte na ssh akceptują tę samą opcję:

scp -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps report.tar.gz deploy@203.0.113.10:/tmp/
rsync -av -e "ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps" ./site/ deploy@203.0.113.10:/srv/site/
GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps" git clone git@example.com:team/repo.git

Dlaczego błąd pojawia się przy drugim przeskoku

Za pomocą ForwardAgent yes gniazdo agenta jest udostępniane na serwerze, z którym nawiązywane jest połączenie. Polecenie ssh uruchomione na tym serwerze korzysta z lokalnego agenta oraz wszystkich kluczy za pośrednictwem przekierowanego gniazda. Dlatego błąd może pojawić się podczas przeskoku z hosta pośredniego na serwer docelowy, mimo że pierwszy przeskok zakończył się poprawnie. Uruchom echo $SSH_AUTH_SOCK na komputerze pośrednim: pusty wynik oznacza, że agent nie jest dostępny. Ścieżka do gniazda oznacza, że jakiś agent jest dostępny, ale niekoniecznie jest to agent użytkownika, ponieważ agent uruchomiony na tym komputerze ustawia tę samą zmienną. Uruchom tam również ssh-add -l: jeśli wyświetla klucze z własnego komputera, przekazywanie jest aktywne.

Przekazywanie agenta wiąże się z dodatkowym ryzykiem. Każdy, kto ma uprawnienia root na komputerze pośrednim, może używać agenta do uwierzytelniania jako użytkownik przez cały czas trwania sesji. ProxyJump pozwala uniknąć obu problemów:

ssh -J deploy@jump.example.com deploy@10.0.0.5

ProxyJump nawiązuje połączenie przez hosta pośredniego i uwierzytelnia na serwerze docelowym z własnego komputera. Dzięki temu lokalne ~/.ssh/config obowiązuje na każdym przeskoku, w tym na IdentitiesOnly. Wyłączenie ForwardAgent jest standardowym krokiem podczas zabezpieczania SSH na VPS.

Czy należy zwiększyć MaxAuthTries na serwerze?

Zwykle nie. Najpierw sprawdź bieżącą wartość:

sudo sshd -T | grep -i maxauthtries

sshd -T wyświetla efektywną konfigurację wraz z wartościami domyślnymi, dlatego pokazuje rzeczywistą wartość nawet wtedy, gdy sshd_config niczego o niej nie określa. Dodaj -C user=deploy,host=example.com,addr=203.0.113.10, jeśli używane są bloki Match, ponieważ są one oceniane dla każdego połączenia i w przeciwnym razie zostaną pominięte.

Zwiększenie limitu rzeczywiście działa, ale tylko w wąskim sensie: większa wartość daje nieprawidłowo działającemu klientowi więcej prób:

MaxAuthTries 20

Zweryfikuj plik i przeładuj usługę. Na czas tej operacji pozostaw otwartą drugą sesję:

sudo sshd -t
sudo systemctl reload ssh      # Debian and Ubuntu
sudo systemctl reload sshd     # RHEL family

Jeśli systemctl is-enabled ssh.socket zgłasza enabled w Ubuntu 24.04, sshd jest uruchamiany przez socket activation. ssh.socket w Ubuntu nie uruchamia nowego demona dla każdego połączenia. Uruchamia ssh.service po nadejściu pierwszego połączenia, a ta usługa pozostaje uruchomiona i obsługuje kolejne połączenia. Powyższe przeładowanie nadal stosuje zmianę. Jeśli ssh.service nie jest jeszcze aktywny, nie ma niczego do przeładowania. Następne połączenie uruchomi usługę z użyciem nowego pliku.

Teraz sprawdź, jaki był skutek tej zmiany. Klient oferuje klucze, których ten serwer nigdy nie zaakceptuje. Zwiększenie limitu powoduje, że serwer przetwarza dwadzieścia odrzuconych ofert na połączenie zamiast sześciu. Dotyczy to każdego łączącego się klienta oraz każdej osoby próbującej odgadnąć hasło w Internecie. Każda oferta wymaga wyszukania w authorized_keys. Logowanie z użyciem własnego klucza nadal trwa długo, ponieważ właściwy klucz wciąż znajduje się na końcu kolejki. Dodanie trzynastego klucza do agenta ponownie doprowadzi do sytuacji wyjściowej i będzie wymagać kolejnego zwiększenia wartości.

Zwiększaj limit wyłącznie wtedy, gdy uprawniony klient rzeczywiście musi przedstawić kilka tożsamości. W każdym innym przypadku popraw konfigurację klienta. Zmniejszenie limitu jest uzasadnionym wzmocnieniem ochrony, gdy każdy użytkownik loguje się przy użyciu skonfigurowanego klucza. Mniejsza wartość daje osobie próbującej odgadnąć dane uwierzytelniające mniej prób w ramach jednego połączenia.

Dlaczego fail2ban może zablokować własny adres

sshd nie zapisuje w dzienniku każdej odrzuconej oferty klucza. Przy domyślnym LogLevel INFO odrzucony klucz dla istniejącego konta jest zapisywany w dzienniku dopiero wtedy, gdy licznik nieudanych prób połączenia osiągnie połowę wartości MaxAuthTries. Właśnie to oznacza zapis z podręcznika: „Once the number of failures reaches half this value, additional failures are logged.” Przy domyślnej wartości 6 pierwsze trzy odrzucone oferty nie są zapisywane w dzienniku. Ostatnie trzy pojawiają się jako wiersze podobne do poniższego, po których występuje wiersz maximum authentication attempts exceeded:

Failed publickey for deploy from 203.0.113.10 port 51292 ssh2: ED25519 SHA256:AAAA...

Te wiersze wyglądają jak wiele nieudanych prób, ale filtr fail2ban sshd ich nie zlicza. Dostarczona domyślnie konfiguracja publickey = nofail odczytuje wiersz Failed publickey dotyczący prawidłowego użytkownika wyłącznie w celu pobrania adresu i nazwy użytkownika. Zliczany jest wiersz maximum authentication attempts exceeded, dlatego jedno połączenie, które osiągnie limit, zwiększa licznik nieudanych prób o 1, a nie o kilka. Jail blokuje adres źródłowy, gdy w ciągu findtime wystąpi maxretry nieudanych prób. Własna konfiguracja fail2ban jail.conf ustawia te wartości odpowiednio na 5 i 10 minut. Około pięciu nieudanych połączeń w ciągu 10 minut wystarczy, aby zablokować własny adres. Skrypt lub narzędzie, które ponawia próbę w pętli, osiągnie ten limit bardzo szybko.

Objaw ulega wtedy zmianie. Zamiast komunikatu „Too many authentication failures” nie pojawia się już nic: połączenie zawiesza się i ostatecznie kończy przekroczeniem limitu czasu, ponieważ zapora odrzuca teraz pakiety bez odpowiedzi. Przekroczenie limitu czasu w sytuacji, w której wcześniej pojawiał się komunikat o błędzie, jest sygnałem rozpoznawczym. To rozróżnienie opisano w Odrzucenie połączenia SSH a przekroczenie limitu czasu połączenia.

Z konsoli dostawcy lub z innego adresu sprawdź jail i usuń blokadę:

sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 203.0.113.10

Podczas diagnozowania klienta wpisz własny adres w ignoreip w jail.local. Po zakończeniu usuń go z powrotem. Konfigurację samego jail opisano w przewodniku po fail2ban dla Ubuntu 24.04.

Co zrobić raz, aby problem nie powracał

Dla każdego serwera należy utworzyć osobny blok Host w pliku ~/.ssh/config, zawierający parametry HostName, User, IdentityFile oraz IdentitiesOnly yes. Dzięki temu polecenie ssh vps jest krótkie, oferuje dokładnie jeden klucz i nie powoduje błędu MaxAuthTries, niezależnie od liczby wpisów w agencie. Pozwala to również zachować zwięzłość danych wyjściowych ssh -v, co ułatwia diagnostykę w przypadku wystąpienia innych awarii.

FAQ

Jak natychmiast naprawić błąd „Too many authentication failures”?

Należy zaoferować jeden klucz zamiast wszystkich. Aby natychmiast nawiązać połączenie, należy uruchomić ssh -o IdentitiesOnly=yes -i ~/.ssh/your_key user@host. Aby naprawić problem trwale, należy dodać blok do ~/.ssh/config, zawierający HostName, User i IdentityFile wskazujące ten klucz oraz IdentitiesOnly yes, a następnie uruchomić chmod 600 ~/.ssh/config. Należy potwierdzić konfigurację za pomocą ssh -v. Dla tego hosta powinien być widoczny jeden wiersz Offering public key:.

Dlaczego ssh -i nadal oferuje inne klucze?

Ponieważ -i dodaje tożsamość do listy, ale nie ogranicza tej listy. Klucze załadowane w ssh-agent pozostają na liście i nadal są oferowane, często przed wskazanym kluczem. Serwer może więc osiągnąć MaxAuthTries, zanim wskazany klucz zostanie użyty. -o IdentitiesOnly=yes jest opcją ograniczającą ssh do wskazanych tożsamości. Należy użyć razem -i i -o IdentitiesOnly=yes albo użyć -o IdentityAgent=none, aby całkowicie pominąć agenta dla tego jednego połączenia.

Czy należy zwiększyć MaxAuthTries na serwerze, aby naprawić ten problem?

Nie, w niemal każdym przypadku. Klient wysyła klucze, których serwer nigdy nie zaakceptuje. Wyższy limit powoduje tylko, że serwer sprawdza więcej odrzuconych ofert w ramach każdego połączenia, dla każdego klienta i każdej próby brute force, która do niego dociera. Problem powróci również po załadowaniu kolejnego klucza do agenta. Wartość efektywną można sprawdzić za pomocą sudo sshd -T | grep -i maxauthtries, ale problem należy naprawić po stronie klienta, używając IdentitiesOnly.

Dlaczego problem pojawił się na serwerze, który w zeszłym miesiącu działał poprawnie?

Agent zawiera teraz więcej kluczy. AddKeysToAgent yes w ~/.ssh/config utrzymuje załadowany każdy używany klucz, a agenty pulpitu typu keyring samodzielnie ładują klucze podczas logowania. Po przekroczeniu przez liczbę załadowanych kluczy wartości MaxAuthTries na serwerze połączenia z każdym serwerem, którego klucz znajduje się daleko na liście ofert, zaczynają kończyć się niepowodzeniem. Należy uruchomić ssh-add -l i porównać liczbę kluczy z limitem ustawionym na serwerze.

Czy fail2ban może zablokować mój adres IP z tego powodu?

Tak, choć nastąpi to wolniej, niż wynikałoby z dziennika serwera. Domyślny filtr sshd w fail2ban nie zlicza wierszy Failed publickey dotyczących prawidłowego użytkownika. Zlicza wiersz maximum authentication attempts exceeded, więc każde połączenie, które osiągnie limit, jest traktowane jako jedno niepowodzenie. Przy dostarczanych domyślnie wartościach maxretry = 5 i findtime = 10m około pięciu takich połączeń w ciągu dziesięciu minut powoduje zablokowanie adresu. Wskazuje na to zmiana błędu w zawieszenie, a następnie przekroczenie limitu czasu, ponieważ pakiety są odrzucane zamiast otrzymywać odpowiedź. Blokadę należy usunąć z konsoli za pomocą sudo fail2ban-client set sshd unbanip <your address>, a następnie naprawić konfigurację klienta przed ponownym połączeniem.

#ssh#ssh-agent#openssh#ssh-config#troubleshooting