Znalezienie poniższych informacji nie jest banalnie proste (choć też nie jakoś niesamowicie skomplikowane), więc po własnych owocnych poszukiwaniach postanowiłem napisać mały poradnik (może komuś się kiedyś przyda

).
Założenia:
- w jednej sieci LAN są (co najmniej) dwa routery pracujące pod kontrolą OpenWRT (router A (
z którego chcemy się łączyć) 192.168.1.1 i router B (
na który chcemy się łączyć) 192.168.1.2)
- chcemy mieć możliwość łączenia się pomiędzy nimi po ssh bez konieczności podawania hasła (np w celu wykorzystania tego w skryptach, lub dla zwykłej wygody)
- klucze przechowujemy w katalogu /etc/dropbear/ (niech ktoś napisze, jeżeli konwencje w tej kwestii są inne)
Niby w sieci jest pełno poradników jak to zrobić ale zdecydowana większość z nich zakłada posiadanie na maszynie klienckiej openSSH (lub czegoś posiadającego polecenie ssh-keygen), a pod OpenWRT domyślnie jest dropbear (owszem, można zmienić, tylko po co?).
Nawet na wiki OpenWRT znalazłem tylko informacje o logowaniu się bez hasła
na router.
Do rzeczy.
1. Generowanie kluczy (router A)Do wygenerowania kluczy służy polecenie dropbearkey. Można się nim posłużyć np w następujący sposób:
cd /etc/dropbear/
dropbearkey -t rsa -f key.priv | grep ssh-rsa > key.pub
Otrzymujemy klucz prywatny (key.priv), który należy trzymać w tajemnicy, oraz publiczny (key.pub), który trzeba przekazać maszynie, na którą chcemy się logować.
Skopiowanie klucza publicznego na drugi router można wykonać poleceniem (tym razem jeszcze trzeba podać hasło

):
scp key.pub 192.168.1.2:/tmp
2. Dodawanie autoryzowanych kluczy publicznych (router B)Skopiowany do /tmp klucz publiczny routera A należy dodać do listy kluczy autoryzowanych (druga linijka nie jest konieczna przy dodawaniu kolejnych kluczy):
cat /tmp/key.pub >> /etc/dropbear/authorized_keys
chmod 0600 /etc/dropbear/authorized_keys
3. Logowanie przy pomocy klucza (router A)dropbear wymaga każdorazowego wyspecyfikowania, że chcemy połączyć się używając wygenerowanego klucza. Służy do tego opcja -i:
ssh -i /etc/dropbear/key.priv 192.168.1.2
Jeżeli nie chcemy podawać tego za każdym razem, możemy zrobić sobie alias:
alias ssh='ssh -i /etc/dropbear/key.priv'
Można też sprawić, by zawsze tworzył się automatycznie (ponownie - nie znam konwencji - jeśli nie jest to dobre miejsce na aliasy, niech ktoś podpowie lepsze):
echo "alias ssh='ssh -i /etc/dropbear/key.priv'" >> /etc/profile
Po tej operacji wystarczy zwykłe
ssh 192.168.1.2
To samo można zrobić np dla scp.
Oczywiście nic nie stoi na przeszkodzie by skonfigurować takie połączenia także w drugą stronę (z routera B na router A), lub dla większej ilości maszyn (na każdej klucze generujemy tylko raz, za to kopiujemy je (i dodajemy do listy autoryzowanych) na wszystkie, na które chcemy się logować).
I to właściwie tyle (prawda, ze proste?).
Wszelkie uwagi i sugestie mile widziane.
----- Dodano ----- 11 maja 2011, o 23:51 -----
4. SSH wywoływane automatycznieWszystko działa ładnie, gdy ssh (lub skrypt je zawierający) wywoływane jest "ręcznie" z linii poleceń. Jednak gdy chcemy, by wywołanie nastąpiło automatycznie (start routera, cron, zdarzenie hotplug, plugin exec z lcd4linux, itp) mogą pojawić się problemy.
4a. Plik /root/.ssh/known_hosts i zmienna $HOMEssh szuka identyfikatorów znanych hostów w pliku
$HOME/.ssh/known_hosts. Gdy logujemy się na router, zmienna $HOME zostaje ustawiona tak, jak jest to zapisane w pliku /etc/passwd (np "/root" dla użytkownika root). cron robi to samo przed uruchomieniem poleceń, ale np hotplug już nie (zawartość tej zmiennej jest ustawiona na "/"). Powoduje to, że ssh szuka hostów w pliku
/.ssh/known_hosts (a nie w
/root/.ssh/known_hosts gdzie zostały zapisane hosty zatwierdzone przez użytkownika w trybie interaktywnym), nie znajduje ich i rozłącza połączenie.
Można temu zapobiec na kilka sposobów:
- ustawiając zmienną $HOME na odpowiednią wartość przed wywołaniem ssh
- tworząc link
/.ssh/known_hosts wskazujący na plik
/root/.ssh/known_hosts (lub na odwrót)
- dodając do polecenia ssh opcję
-y (zezwala na połączenie, gdy host jest nieznany)
Ta ostatnia opcja może być nieco niebezpieczna, ale też może się przydać, gdy chcemy się łączyć z hostami, których nie zatwierdziliśmy wcześniej (z lenistwa, lub braku możliwości) w trybie interaktywnym.
4b. stdout i stderrRozwiązanie tego problemu zajęło mi więcej czasu i szczerze mówiąc nadal nie do końca rozumiem przyczynę. Ale skoro się udało, to może ktoś z tego skorzysta.
Jeżeli chcemy tylko wykonać komendę na zdalnym rządzeniu, nie ma problemu, np:
/usr/bin/ssh -i /etc/dropbear/key.priv root@192.168.1.2 "/bin/touch /tmp/file"
(komenda wykona się - zostanie utworzony plik)
Jeżeli jednak interesuje nas to, co dana komenda zwraca (na standardowe wyjście, lub na wyjście błędów), sprawa robi się nieco bardziej skomplikowana.
Np. polecenie:
/usr/bin/ssh -i /etc/dropbear/key.priv root@192.168.1.2 "/usr/bin/uptime" > /tmp/remote_host_uptime
spowoduje utworzenie pustego pliku (0 bajtów).
Jak nadmieniłem, nie do końca rozumiem przyczynę (ale ponoć ma to coś wspólnego z tym, że ssh wywołane w ten sposób przekierowuje swoje wejście, co powoduje też przekierowanie wyjść).
W przypadku "pełnego" ssh podobno wystarczy dodanie opcji -n (zakaz przekierowywania), ale dropbear, jako klient, nie posiada jej.
Rozwiązaniem jest ręczne przekierowanie wejścia np na
/dev/zero (z
/dev/null nie dizała):
/usr/bin/ssh -i /etc/dropbear/key.priv root@192.168.1.2 "/usr/bin/uptime" < /dev/zero > /tmp/remote_host_uptime
Teraz już dostaniemy zarówno stdout, jak i stderr ze zdalnie wykonanej komendy.
Jest to jedyny sposób, jaki znalazłem (np proba wymuszenia emulacji pty, poprzez wielokrotną opcję -t nie pomaga) i, choć może nie najbardziej elegancki, to jednak skuteczny.
Jak zwykle chętnie przyjmę wszelkie uwagi, pomysły i opinie.