Uproszczenie korzystania z SSH przy zastosowaniu kluczy OpenSSH

Klucze SSH mogą być wykorzystane jako sposób identyfikacji danej osoby przy logowaniu się do zdalnego serwera SSH. Te klucze zawsze występują w parach -- jeden prywatny, drugi publiczny. Pierwszy z nich jest znany tylko nam i powinien być trzymany w sekrecie i pilnie strzeżony. Klucz publiczny z kolei zaś jest przesyłany na każdy serwer SSH, z którym chcemy się połączyć. Gdy serwer jest w posiadaniu naszego klucza publicznego i widzi przy tym, że próbujemy nawiązać połączenie, używa on tego klucza by wysłać do nas zapytanie (challange) -- jest ono zakodowane i musi na nie zostać udzielona odpowiednia odpowiedź, a tej może dokonać ktoś, kto jest w posiadaniu klucza prywatnego. Nie ma innej opcji by rozkodować wiadomość, dlatego też nikt inny nie może udzielić na nią prawidłowej odpowiedzi. To rozwiązanie eliminuje wrażliwość na różne formy podsłuchu -- ten kto nasłuchuje nie będzie w stanie przechwycić pakietów zawierających hasło, bo ono nie jest nigdy transmitowane prze sieć. No i oczywiście jeśli chodzi o samo hasło -- odpadają nam ataki bruteforce pod kątem jego złamania.
Jako, że klucze SSH zawierają wrażliwe informacje, można je zaszyfrować, tak by każdorazowe ich wykorzystanie wymagało podania hasła ale wtedy przy logowaniu się do serwera trzeba podać hasło do klucza zamiast do konta, co niekoniecznie może być wygodniejsze w przypadku ciągłego wywoływania polecenia ssh lub scp . Niemniej jednak, na linuxach mamy do dyspozycji narzędzia, np. gpg-agent, które to pozwalają na dodanie i przechowywanie szeregu kluczy i udzielaniu do nich dostępu przy wykorzystaniu tylko jednego hasła. W taki sposób możemy zdefiniować wiele kluczy, przechowywać je w bezpieczny sposób i mieć tylko jedno hasło by nimi wszystkimi zarządzać. W przypadku gpg-agenta , możemy także ustawić czas dostępu do klucza. Po jego upłynięciu, trzeba będzie ponownie wprowadzić hasło by wydobyć klucz od agenta, a przez ten zdefiniowany okres czasu, możemy się posługiwać kluczem bez podawania jakichkolwiek haseł.

Ten artykuł zakłada poprawne skonfigurowanie gpg-agenta lub innego narzędzia oddelegowanego do zarządzania kluczami SSH.

Wybór i generowanie klucza

Są różne typy kluczy SSH -- zwykle wykorzystuje się klucze RSA 1024/2048/4096 bitowe. Innym typem klucza jest ECDSA , który to opiera się o krzywe eliptyczne zapewniając ten sam poziom bezpieczeństwa co klucze RSA, z tym, że sam klucz w przypadku ECDSA jest o wiele krótszy. Istnieje jeszcze inny typ klucza -- ED25519, który to jest zmodyfikowaną wersją ECDSA i powstał w odpowiedzi na podejrzenia pod kątem NSA, czy prawdziwe, tego nie wiem. Na necie natomiast można się natknąć na informację, że te krzywe wykorzystywane przy ECDSA nie są chyba aż tak idealnie krzywe czy coś i mogą stanowić zagrożenie bezpieczeństwa. W każdym razie, poniżej jest tabelka porównująca długość poszczególnych kluczy:

Symmetric  |  ECC2N  |  ECP  |  DH/DSA/RSA
	   80  |   163   |  192  |     1024
	  128  |   283   |  256  |     3072
	  192  |   409   |  384  |     7680
	  256  |   571   |  521  |    15360

Jak widzimy, zaledwie 521 bitów wystarczy by zapewnić poziom bezpieczeństwa, który można uzyskać stosując klucze RSA 15360 bitów. Problem w tym, że domyślnie dropbear nie obsługuje kluczy SSH innych niż RSA i by mieć obsługę tych dwóch dodatkowych typów, trzeba rekompilować źródła. W każdym razie, zostaniemy przy kluczach RSA.

By wygenerować taką parę kluczy, wpisujemy w terminalu poniższą linijkę:

$ ssh-keygen -t rsa -b 4096 -C "$(whoami)@$(hostname)-$(date -I)"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/morfik/.ssh/id_rsa): /home/morfik/.ssh/id_rsa_router
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/morfik/.ssh/id_rsa_router.
Your public key has been saved in /home/morfik/.ssh/id_rsa_router.pub.
The key fingerprint is:
5d:2d:a2:24:78:43:a3:1b:82:1d:3d:cb:c0:be:ef:28 morfik@morfikownia-2014-10-24
The key's randomart image is:
+

---[RSA 4096]----+
| ... o |
| oo.o+ . . |
|..oo+o+ . . o . |
| ..o+ + o o . |
| .. S . |
| . |
| . |
|E .. |
| .... |
+-----------------+

Jeśli nie wprowadzimy hasła do klucza, nie zostanie on zaszyfrowany i nie będziemy musieli podawać żadnych haseł przy łączeniu się przez ssh do routera.
Powstały w ten sposób klucz jest przechowywany w katalogu ~/.ssh . Każdy może go podejrzeć, dlatego warto też zadbać o odpowiednie prawa dostępu do plików ale trzeba przy tym pamiętać o jednej istotniej rzeczy -- użytkownik root może i tak obejść te ograniczenia dostępu i jeśli nie ufamy adminowi, lepiej nie trzymać w jego systemie kluczy prywatnych. W każdym razie, jeśli to my jesteśmy administratorem systemu i przy tym mamy w nim wielu użytkowników, możemy zabezpieczyć swoje klucze przed nieuprawnionym dostępem:

$ chmod 700 .ssh/
$ chmod 600 ~/.ssh/*

Przesyłanie klucza publicznego

Przy tworzeniu pary kluczy, zostały stworzone dwa pliku -- id_rsa_router oraz id_rsa_router.pub .Pierwszy z nich to klucz prywatny i go zostawiamy w spokoju. Z kolei ten drugi trzeba przesłać na router. Robimy to przy pomocy scp :

$ scp ~/.ssh/id_rsa_router.pub root@192.168.1.1:
root@192.168.1.1's password:
id_rsa_router.pub               100%  744     0.7KB/s   00:00

W pierwszej linijce, po adresie hosta jest dodany : -- określa on katalog domowy, nie trzeba podawać ścieżki typu /root/ zamiast niego. Logujemy się teraz na router:

$ ssh root@192.168.1.1
root@192.168.1.1's password:
...
root@the-mountain:~# ls -al
drwxr-xr-x    1 root     root             0 Oct 24 01:13 .
drwxr-xr-x    1 root     root             0 Oct 23 23:58 ..
-rw-------    1 root     root           744 Oct 24 01:13 id_rsa_router.pub

I dodajemy zawartość przesłanego pliku do /etc/dropbear/authorized_keys :

root@the-mountain:~# cat id_rsa_router.pub >> /etc/dropbear/authorized_keys
root@the-mountain:~# rm id_rsa_router.pub
root@the-mountain:~# exit
Connection to 192.168.1.1 closed.

Logujemy się ponownie w celu sprawdzenia czy klucz działa.

$ ssh root@192.168.1.1

BusyBox v1.22.1 (2014-10-17 21:31:57 CEST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

		_______                     ________        __
	   |       |.-----.-----.-----.|  |  |  |.----.|  |_
	   |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
	   |_______||   __|_____|__|__||________||__|  |____|
				|__| W I R E L E S S   F R E E D O M
 ----------------------------------------------------------------
 |                                                              |
 | OpenWrt Barrier Breaker (r42943)                             |
 | Build time: 2014-10-17 22:39 CEST                            |
 |                                                              |
 | Cezary Jackiewicz (obsy), http://eko.one.pl                  |
 |                                                              |
 ----------------------------------------------------------------
 | Machine: TP-LINK Archer C7                                   |
 | Uptime: 0d, 01:01:41                                         |
 | Load: 0.22 0.13 0.14                                         |
 | Flash: total: 12.3MB, free: 9.8MB, used: 20%                 |
 | Memory: total: 123.4MB, free: 80.9MB, used: 34%              |
 | WAN: 10.1.4.41, proto: dhcp                                  |
 | LAN: 192.168.1.1                                             |
 | WLAN: mode: ap, ssid: Valar_Morghulis, channel: 36           |
 | WLAN: mode: ap, ssid: Ever_Vigilant, channel: 8              |
 ----------------------------------------------------------------
root@the-mountain:~#

Jeśli nie podaliśmy hasła przy tworzeniu party kluczy, zostanie zalogowani bez pytania o hasło klucz. Jeśli zaś podaliśmy hasło wtedy, zostaniemy zapytani o nie ale tylko raz - przez następne 30min nie będziemy musieli go podawać.

Jeśli nuży nas trochę ciągłe wpisywanie root@192.168.1.1 możemy zrezygnować z root@ i podawać sam adres IP podczas łączenia się z konkretną maszyna. W tym celu musimy skonfigurować serwer, do którego się łączymy w pliku ~/.ssh/config:

Host 192.168.1.1
	User root
	IdentitiesOnly yes
	IdentityFile ~/.ssh/id_rsa_router
	CheckHostIP yes
	Port 22

W powyższym pliku można zdefiniować wiele takich bloków.

Dodatkowe zabezpieczenia

By dodatkowo zwiększyć bezpieczeństwo serwera, przydałoby się wyłączyć możliwość logowania przy pomocy hasła -- w przypadku gdy ktoś trzeci będzie się chciał podłączyć do serwera i nie będzie przy tym posiadał klucza prywatnego, będzie on mógł w dalszym ciągu próbować odgadnąć hasło do konta root. By zrezygnować z uwierzytelniania opartego o hasło, edytujemy na routerze plik /etc/config/dropbear i przepisujemy go do poniższej postaci:

config dropbear
	option PasswordAuth 'off'
	option RootPasswordAuth 'off'
	option RootLogin '1'
	option Port         '22'
#	option BannerFile   '/etc/banner'
	option Interface 'br-lan'
	option IdleTimeout '300'

Po wyłączeniu logowania z użyciem haseł, jeśli stracimy klucz prywatny, nie dostaniemy się wtedy do serwera:

morfik:~$ ssh 192.168.1.1
The authenticity of host '192.168.1.1 (192.168.1.1)' can't be established.
RSA key fingerprint is 5d:2d:a2:24:78:43:a3:1b:82:1d:3d:cb:c0:be:ef:28.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.1' (RSA) to the list of known hosts.
Permission denied (publickey).

Warto o tym pamiętać.