Uwaga: Oryginalna wersja tego artykułu została opublikowana w IBM developerWorks i jest własnością Westtech Information Services. Poniższy dokument jest poprawioną przez zespół GDP wersją oryginalnego tekstu i nie jest już aktualizowany.

Zarządzanie kluczem OpenSSH, Część 2

Daniel Robbins  Autor
Jacek Noszczyk  Tłumaczenie

Zaktualizowano 9 października 2005

1.  Wprowadzenie do ssh-agent i keychain

Kilka słów o ssh-agent

ssh-agent (część pakietu OpenSSH), to program specjalnie zaprojektowany do pracy z kluczami RSA i DSA (więcej informacji w pierwszym artykule z tej serii od wstępu do uwierzytelnienia RSA i DSA). ssh-agent jest demonem zaprojektowanym w celu buforowania odszyfrowanych kluczy prywatnych.

ssh zawiera wbudowane wsparcie, umożliwiające mu komunikację z ssh-agent i pozwala na posiadanie odszyfrowanych kluczy prywatnych bez konieczności potwierdzania hasła przy każdym nowym połączeniu. W tym celu należy po prostu użyć ssh-add żeby dodać klucz prywatny do pamięci podręcznej agenta ssh. Jest to jednorazowy proces; po użyciu ssh-add, ssh przechwyci klucz prywatny od ssh-agent, zamiast czekać na potwierdzenie hasła.

Używanie ssh-agent

Spójrzmy jak działa system buforowania kluczy. Kiedy ssh-agent się uruchamia, zwraca kilka ważnych zmiennych środowiskowych przed odłączeniem od powłoki i kontynuowaniem pracy w tle. Oto kilka przykładowych wydruków wygenerowanych przez ssh-agent w momencie uruchomienia:

Listing 1.1: Uruchomienie demona ssh-agent

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-XX4LkMJS/agent.26916; export SSH_AUTH_SOCK;
SSH_AGENT_PID=26917; export SSH_AGENT_PID;
echo Agent pid 26917;

Jak widać wydruk ssh-agenta jest w rzeczywistości serią komend basha; jeżeli zostaną wykonane, spowodują ustawienie pary zmiennych środowiskowych, SSH_AUTH_SOCK i SSH_AGENT_PID. Za sprawą komendy export, zmienne te będą dostępne dla innych komend uruchomionych później. Wszystko to stałoby się jeżeli zmienne te były używane przez powłokę, ale teraz są po prostu drukowane na standardowe wyjście. Aby to naprawić można wywołać ssh-agent w następujący sposób:

Listing 1.2: Różne sposoby wywołania ssh-agent

$ eval `ssh-agent`

Komenda ta mówi bashowi żeby uruchomił ssh-agent a następnie ocenił wyjście ssh-agenta. Wywołanie w ten sposób (z odwrotnym cudzysłowem) powoduje, że zmienne SSH_AGENT_PID i SSH_AUTH_SOCK są ustawiane i exportowane przez powłokę, są dostępne dla każdego nowego procesu uruchomionego w trakcie sesji logowania.

Najlepszym sposobem na uruchomienie ssh-agent jest dodanie powyższej linii do pliku ~/.bash_profile. W ten sposób, wszystkie programy uruchomione w powłoce logowania zobaczą zmienne środowiskowe, będą w stanie zlokalizować ssh-agent i w razie potrzeby zapytać go o klucze. SSH_AUTH_SOCK jest zmienną środowiskową szczególnie ważną; SSH_AUTH_SOCK zawiera ścieżkę do gniazda domeny UNIX, którego ssh i scp moga użyć w celu nawiązania łączności z ssh-agent.

Używanie ssh-add

ssh-agent startuje z pustym buforem odszyfrowanych kluczy prywatnych. Zanim będzie można użyć ssh-agent, trzeba najpierw dodać klucz(e) prywatny(e) do bufora ssh-agentam, co umożliwia polecenie ssh-add. W poniższym przykładzie, użyto ssh-add w celu dodania ~/.ssh/identity klucza prywatnego RSA do bufora ssh-agenta:

Listing 1.3: Ładowanie klucza prywatnego RSA do bufora ssh-agenta

$ ssh-add ~/.ssh/identity
Need passphrase for /home/drobbins/.ssh/identity
Enter passphrase for /home/drobbins/.ssh/identity
(enter passphrase)

Jak widać, ssh-add zapytał o hasło po to aby gotowy do użycia klucz prywatny mógł być odszyfrowany i przechowany w buforze ssh-agenta. Kiedy użyto ssh-add w celu dodania klucza(kluczy) prywatnego do bufora ssh-agenta i zmienna SSH_AUTH_SOCK jest zdefiniowana w bieżącej powłoce (i tak powinno być, ponieważ uruchomiono ssh-agent z ~/.bash_profile), wtedy mona użyć scp i ssh w celu nawiązania połączenia ze zdalnymi systemami bez podawania hasła.

Limity ssh-agenta

ssh-agent jest naprawdę wspaniały, ale jego trudna konfiguracja wciąż pozostawia nas z kilkoma pomniejszymi niedogodnościami. Oto one:

Po pierwsze, z eval `ssh-agent` w pliku ~/.bash_profile, nowa kopia ssh-agent jest uruchamiana dla każdej sesji logowania. Oznacza to że trzeba użyć ssh-add żeby dodać klucz prywatny dla każdej nowej kopii ssh-agent. Jeśli jest otworzony jeden terminal lub konsola, nie ma to wielkiego znaczenia, ale zazwyczaj otwartych jest kilka terminali i trzeba wpisać hasło za każdym razem gdy otwierana jest nowa konsola. Technicznie rzecz biorąc, nie ma powodu dla którego trzeba by to robic, ponieważ pojedynczy proces ssh-agent powinien wystarczyć.

Inny problem z domyślnym ustawieniem ssh-agent jest taki, że nie jest zgodny z żądaniami crona. Odkąd procesy są uruchomione przez crona, nie będą dziedziczyć zmiennej SSH_AUTH_SOCK z ich środowiska i przez to nie będą wiedziały, że proces ssh-agent jest uruchomiony albo jak się z nim skontaktować. Ten problem można naprawić.

Wprowadzenie keychain

Aby rozwiązać te problemy, napisano w bashu program o nazwie keychain. keychain umożliwia używanie procesu ssh-agent jednego na system, a nie na sesje logowania. Oznacza to, że dla każdego klucza prywatnego trzeba wykonać tylko raz ssh-add. Jak widać keychain pomaga również optymalizować proces ssh-add poprzez próbę dodania kluczy prywatnych, które nie są w buforze działającego ssh-agenta.

Oto przebieg działania keychain. Jeżeli jest uruchomiony z ~/.bash_profile, w pierwszej kolejności sprawdzi czy ssh-agent został już uruchomiony. Jeżeli nie, wtedy uruchomi ssh-agent i zapisze ważne zmienne SSH_AUTH_SOCK i SSH_AGENT_PID w pliku ~/.ssh-agent dla bezpieczeństwa i do przyszłego użycia. Oto najlepszy sposób na uruchomienie keychain; tak jak w przypadku użycia czystego ssh-agent, umieszczamy odpowiednie ustawienia wewnątrz ~/.bash_profile:

Listing 1.4: Ustawienia dla ssh-agent w pliku ~/.bash_profile

#!/bin/bash
#example ~/.bash_profile file
/usr/bin/keychain ~/.ssh/id_rsa
#redirect ~/.ssh-agent output to /dev/null to zap the annoying
#"Agent PID" message
source ~/.ssh-agent > /dev/null

Jak widać, za pomocą keychain pobieramy plik źródłowy ~/.ssh-agent zamiast oceniać wydruk wyjściowy jak to było robione w przypadku bezpośredniego użycia ssh-agent. Jednak rezultat jest taki sam -- zmienna SSH_AUTH_SOCK jest zdefiniowana, ssh-agent uruchomiony i gotowy do użycia. Ponieważ zmienna SSH_AUTH_SOCK jest zapisana w ~/.ssh-agent, skrypty powłoki i zadania crona mogą w prosty sposób połączyć się z ssh-agent pobierając plik źródłowy ~/.ssh-agent. Sam keychain również korzysta z tego pliku. W momencie uruchomienia sprawdza czy ssh-agent jest uruchomiony. Jeżeli tak, używa pliku ~/.ssh-agent do pobrania właściwych ustawień SSH_AUTH_SOCK, umożliwiających mu użycie istniejącego agenta zamiast uruchamianie nowego. keychain uruchomi nowy proces ssh-agent tylko jeżeli plik ~/.ssh-agent jest przestarzały (wskazuje na nieistniejący ssh-agent) lub jeśli ~/.ssh-agent po prostu nie istnieje.

Instalacja keychain

Instalacja keychain jest prosta. Najpierw, zaglądamy na stronę projektu keychain i sciągamy najnowszą dostepną wersję spakowanych źródeł keychain lub instalujemy go w następujący sposób używając emerge:

Listing 1.5: Instalacja keychain

# emerge keychain

Teraz kiedy keychain jest w /usr/bin/, należy go dodać do ~/.bash_profile, podając ścieżki do kluczy prywatnych jako argumenty. Oto standardowy plik z poprawnie aktywowanym keychain ~/.bash_profile:

Listing 1.6: Aktywowanie keychain w pliku ~/.bash_profile

#!/bin/bash
#on this next line, we start keychain and point it to the private keys that
#we'd like it to cache
/usr/bin/keychain ~/.ssh/id_rsa ~/.ssh/id_dsa
source ~/.ssh-agent > /dev/null
#sourcing ~/.bashrc is a good thing
source ~/.bashrc

Keychain w akcji

Po skonfigurowaniu pliku ~/.bash_profile żeby wywoływał keychain przy każdym logowaniu, wylogowaniu i powtórnym logowaniu, keychain będzie uruchamiał ssh-agent, zapamiętywał ustawienia zmiennych środowiskowych agenta w pliku ~/.ssh-agent, a potem prosił o podanie hasła dla każdego klucza prywatnego podanego jako argument wiersza poleceń w pliku ~/.bash_profile:


Ilustracja 1.1: Keychain uruchomiony po raz pierwszy

Fig. 1

Po wpisaniu hasła klucze prywatne zostaną dodane do bufora i keychain zakończy działanie. Następnie pobierane są informacje z pliku ~/.ssh-agent i zostaje zainicjowana sesja logowania do użycia przez ssh-agent. Teraz, jeżeli nastąpi wylogowanie i powtórne logowanie, keychain sam odnajdzie istniejący proces ssh-agent, który nie zakończył się gdy nastąpiło wylogowanie. Dodatkowo, keychain zweryfikuje to czy klucze prywatne które były wpisane znajdują się już w buforze ssh-agenta. Jeżeli nie, wtedy trzeba będzie podać właściwe hasło, ale jeżeli wszystko pójdzie dobrze, istniejąca wersja ssh-agenta wciąż będzie zawierać poprzednio dodane klucze prywatne. Dzięki temu nie trzeba ponownie podawac hasła:


Ilustracja 1.2: Keychain odnajduje istniejącego ssh-agenta

Fig. 2

Po zalogowaniu będzie można kopiować (scp) i logować (ssh) się zdalnie. Nie trzeba korzystać z ssh-add po zalogowaniu się, również ssh i scp nie będą prosiły o podanie hasła. W rzeczywistości, dopóki początkowy proces ssh-agenta jest uruchomiony, będzie można się zalogować i nawiązać połączenia ssh bez konieczności podawania hasła. ssh-agent może kontynuować swoje działanie do momentu, gdy komputer zostanie ponownie uruchomiony. W związku z tym, że zwykle tych ustawień dokonuje się na Linuksie, istnieje możliwość pominięcia wpisywania hasła przez kilka miesięcy. Witamy w świecie bezpiecznych połączeń z uwierzytelnianiem RSA i DSA bez konieczności podawania hasła.

Nawet po stworzeniu kilku nowych sesji logowania widać, że keychain podłączy się za każdym razem do tego samego procesu ssh-agenta. Można również podłączyć skrypty i działające procesy crona do uruchomionego ssh-agenta. Żeby używać komend ssh lub scp ze skryptów powłoki i procesów crona, należy się upewnić, że najpierw pobierają informacje z pliku ~/.ssh-agent:

Listing 1.7: Pobieranie informacji z pliku ~/.ssh-agent

$ source ~/.ssh-agent

Następnie każda kolejna komenda ssh lub scp będzie mogła znaleźć bieżącego ssh-agenta i nawiązać bezpieczne połączenie bez konieczności podawania hasła, tak jak można to wykonać z powłoki.

Opcje keychaina

Kiedy keychain jest uruchomiony i działa, można wydać polecenie keychain --help, które wyświetli listę paramtetrów tego programu. Tu zajmiemy się szczególnie opcją --clear.

W pierwszej części wytłumaczyłem, że używanie niezaszyfrowanych kluczy prywatnych jest niebezpieczne, ponieważ ktoś mógłby ukraść klucz prywatny i użyć go do zalogowania się na zdalne konto z jakiegokolwiek systemu bez konieczności podawania hasła. Dopóki keychain nie jest wrażliwy na tego typu nadużycia (dopóki klucze prywatne są zaszyfrowane), istnieje potencjalna wada bezpośrednio związana z faktem, że keychain umożliwia łatwe podłączenie się do długo działającego procesu ssh-agenta. Co by się stało gdyby ktoś odgadł hasło i zalogował się do lokalnego systemu? Jeżeli byłby w stanie zalogować się jako normalny użytkownik, keychain automatycznie dałby mu dostęp do odszyfrowanych kluczy prywatnych, umożliwiając dostęp do innych kont użytkownika.

Nim przejdziemy dalej. Zatrzymajmy się przy wątku dotyczącym bezpieczeństwa. Jeżeli jakiś złośliwy użytkownik był w stanie zalogować się na nasze konto, keychain rzeczywiście umożliwi mu dostęp do naszych zdalnych kont. Jednak intruzowi będzie bardzo ciężko ukraść nasze odszyfrowane klucze prywatne ponieważ one wciąż znajdują sią na dysku i są zaszyfrowane. Dodatkowo, aby zdobyć dostęp do kluczy prywatnych intruz musi zalogować się jako użytkownik, a nie tylko przejrzeć pliki z jego katalogu. Zatem ominięcie ssh-agenta będzie o wiele trudniejszym zadaniem niż zwykła kradzież niezaszyfrowanego klucza prywatnego, które wymaga tylko dostępu intruza do plików w katalogu ~/.ssh. Jeśli jednaki intruz był w stanie zalogować się jako użytkownik, mógł uczynić spore szkody przez używanie zaszyfrowanych kluczy prywatnych. Zatem jeżeli używamy keychain na serwerze, na który się nie logujemy bardzo często lub nie prowadzimy monitorowania naruszenia bezpieczeństwa, wtedy należy używać opcji --clear.

Opcja --clear umożliwia przekazanie keychain, że każde nowe logowanie na konto użytkownika powinno byc traktowane jako potencjalne włamanie, chyba, że zostanie udowodnione, że jest inaczej. Kiedy uruchomimy keychain z opcją --clear, natychmiast wyczyści on wszystkie klucze prywatne z bufora ssh-agenta kiedy nastąpi logowanie, przed rozpoczęciem normalnego działania. Zatem keychain poprosi o podanie hasła zamiast dać dostęp intruzowi do istniejącego zbioru kluczy z bufora. Jednak, nawet to ulepszenie bezpieczeństwa wprowadza pewne niedogodności i jest podobne do działania samego ssh-agenta, bez keychain. Trzeba dokonać wyboru pomiędzy bezpieczeństwem, a wygodą.

Pomimo tego, używanie keychain z opcją --clear wciąż jest lepszym rozwiązaniem niż używanie samego ssh-agent. Należy pamiętać, że kiedy używamy keychain --clear procesy crona i skrypty wciąż będą mogły nawiązać połączenie bez konieczności podawania hasła. Dzieje się tak, ponieważ klucze prywatne zostały wyczyszczone przy zalogowaniu, a nie wylogowaniu. Odkąd wylogowanie z systemu nie stanowi potencjalnego naruszenia bezpieczeństwa, nie ma potrzeby żeby keychain był odpowiedzialny za czyszczenie kluczy ssh-agenta. Zatem opcja --clear stanowi idealny wybór dla niezbyt często używanych serwerów.

Gotowe!

Omówiliśmy metody pracy z kluczami RSA i DSA. Pokazaliśmy jak używać ich do codziennej pracy z OpenSSH w sposób wygodny, ale i z zachowaniem zasad bezpieczeństwa. Poniżej znajduje się kilka adresów, które pozwolą na szersze poznanie tej tematyki.

2.  Źródła