Gentoo Logo

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ęść trzecia

Spis treści:

1.  Poprawki w ssh-agent i keychain

Wielu z nas używa OpenSSH jako bezpiecznej, szyfrowanej alternatywy dla sędziwych już narzędzi telnet i rsh. Jedną z ciekawszych opcji OpenSSH jest jego zdolność do autoryzacji użytkownika używającego protokołów RSA i DSA, które są bazowane na parach depełniających się "kluczy" numerycznych. Jednym z głównych uroków autoryzacji RSA i DSA jest zdolność do ustanawiania połączenia ze zdalnymi systemami bez dostarczania hasła. Aby lepiej to zrozumieć, należy zajrzeć do poprzednich części tej serii, które stanowią odpowiednio uwierzytelnianie RSA/DSA (część pierwsza) oraz ssh-agent i keychain (część druga).

Od września 2001, kiedy to druga część została opublikowana na stronach developerWorks, a następnie wzmiankowana na Slashdot i Freshmeat (w dziale Źródła są odnośniki do tych artykułów) wielu użytkowników zaczęło używać keychain, a on sam uległ wielu zmianom. Dostałem około dwudziestu wysokiej jakości łatek od deweloperów z całego świata. Wiele z tych łatek włączyłem do źródeł keychaina, który jest dostępny obecnie w wersji 1.8 (spójrz do działu Źródła). Wysłałem wiele szczerych podziękowań do wszystkich, którzy przysłali łatki, zgłosili błędy, żądane opcje oraz notki z uznaniem.

Zaostrzenie bezpieczeństwa ssh

W moim ostatnim artykule, poświęciłem sporo czasu na duskusję o wadach i zaletach wynikających z używania ssh-agent. Kilka dni później drugi artykuł pojawił się na developerWorks, a ja otrzymałem e-mail od Charlesa Kerneya z Sarnoff Corporation, w którym autor grzecznie poinformował mnie o nowych możliwościach przykazywania autoryzacji agenta OpenSSH. W uzupełnieniu Charles podkreślił, że używanie ssh-agent na niezaufanych maszynach jest odrobinę niebezpieczne: jeśli ktoś zdoła zdobyć dostęp superużytkownika, wtedy rozszyfrowany klucz może zostać "wyciągnięty" z ssh-agent. Nawet jeśli wyciągnięcie kluczy będzie w pewien sposób trudne, jest to w obrębie umiejętności profesjonalnych włamywaczy. A kradzież klucza prywatnego powinna zmotywować nas do przedsięwzięcia kroków w celu zabezpieczenia się przed podobnymi zdarzeniami.

Aby określić strategię ochrony naszych prywatnych kluczy, przede wszystkim musimy zaklasyfikować maszyny, do których mamy dostęp, do jednej z dwóch kategorii. Jeśli dany host jest dobrze zabezpieczony, powinien zostać uważany za zaufany. Jeśli maszyna jest używana przez wielu użytkowników albo mamy jakiekolwiek inne wątpliwości dotyczące jej zabezpieczeń, wtedy powinna zostać uważana jako niezaufana. Chroniąc nasze klucze prywatne, nigdy nie powinniśmy uruchamiać ssh-agent oraz keychain na niezaufanych maszynach.

Jednakże tworzy to pewne problemy. Jeśli nie można uruchomić ssh-agent na niezaufanych hostach, jak założyć bezpieczne, pozbawione hasła połączenie ssh z tych systemów? Odpowiedź jest tylko jedna: użyć ssh-agent i keychain na zaufanych hostach lub wykorzystać nowe możliwości uwierzytelniania OpenSSH, rozszerzając pozbawione hasła uwierzytelnianie do tych niezaufanych. Uwierzytelnianie działa dzięki zezwoleniu zdalnej sesji ssh do kontaktu z ssh-agent na zaufanych systemach.

Agent przesyłający uwierzytelnianie

Aby zrozumieć ideę działania przesyłu uwierzytelniania, spójrzmy na hipotetyczną sytuację, w której użytkownik drobbins posiada zaufany laptop zwany lappy, zaufany serwer zwany trustbox oraz dwa inne, niezaufane systemy, do których musi mieć dostęp, zwane odpowiednio nottrust1 i nottrust2. Obecnie używa on ssh-agent wraz z keychain na każdej z czterech maszyn, jak jest to pokazane poniżej:


Ilustracja 1.1: ssh-agent używany na zaufanych i niezaufanych maszynach

Fig. 1

Problem pojawia się w momencie, w którym ktoś zyska dostęp superużytkownika na nottrust1 lub nottrust2. Wtedy osoba ta ma możliwość wyciągnięcia kluczy z procesów ssh-agent. Aby naprawić to, drobbins zatrzymuje ssh-agent i keychain na nottrust1 i nottrust2. Aby być jeszcze bardziej ostrożnym, drobbins decyduje się używać tych programów jedynie na laptopie. Limituje to ujawnienie jego rozszyfrowanych kluczy, chroniąc go przed ich kradzieżą.


Ilustracja 1.2: ssh-agent uruchomiony jedynie na laptopie; bardziej bezpieczna konfiguracja

Fig. 2

Oczywiście problem w tym, że drobbins może teraz ustanawiać pozbawione hasła połączenia jedynie z laptopa. Spójrzmy jak umożliwić przesyłanie uwierzytelniania i obejść ten problem.

Zakładając, że wszystkie boxy mają uruchomione najświeższe wersje OpenSSH, nie możemy użyć przekazania uwierzytelniania. Pozwala ono zdalnemu procesowi ssh na kontakt z ssh-agent, który jest uruchomiony na lokalnym, zaufanym hoscie -- raczej jak wymaganie wersji ssh-agent'a, który jest uruchomiony na tej samej maszynie, z której wychodzi połączenie. Zazwyczaj pozwala to na uruchomienie naszego zespołu (ssh-agent i keychain) na zwykłym hoscie i znaczy, że wszystkie połączenia ssh, które pochodzą (bezpośrednio lub pośrednio) z tej maszyny, będą korzystały z lokalnego ssh-agent.

Aby umożliwić przesyłanie uwierzytelniania, dodamy poniższą linię do pliku /etc/ssh/ssh_config, zarówno w lappy jak i trustbox. Zauważ, że jest to plik konfiguracyjny ssh (ssh_config), nie demona sshd (sshd_config):

Listing 1.1: Dodajemy poniższą linię do /etc/ssh/ssh_config

ForwardAgent Yes

Teraz, drobbins spokojnie może połączyć się ze swojego laptopa do trustbox, a wtedy do nottrust1, już bez wpisania hasła. Oba procesy ssh łączą się z ssh-agent uruchomionym na lappy:

Listing 1.2: Tapping lappy

$ ssh drobbins@trustbox
Last login: Wed Sep 26 13:42:08 2001 from lappy

Welcome to trustbox!
$ ssh drobbins@notrust1
Last login: Tue Sep 25 12:03:40 2001 from trustbox

Welcome to notrust1!
$

Jeśli wypróbujesz podobną konfigurację i zauważysz, że przekazywanie nie działa jak należy, spróbuj ssh -A zamiast ssh, aby wyraźnie umożliwić przekazanie autoryzacji. Poniżej jest diagram ukazujący drogę naszego logowania się do trustbox oraz nottrust1 używając przekazywanie uwierzytelniania:


Ilustracja 1.3: Agent w akcji

Fig. 3

Jak można słusznie zauważyć połączenie ssh do trustbox utrzymuje połączenie z ssh-agent uruchomionym na lappy. Kiedy połączenie ssh zostało ustanowione z trustbox do nottrust1, ssh utrzymało uwierzytelnione połączenie, skutecznie rozszerzając łańcuch (chain). To czy łańcuch autoryzacji może zostać rozszerzony poza nottrust1 zależy od tego, jak /etc/ssh/ssh_config jest skonfigurowany. Tak długo, jak ssh-agent jest uruchomiony na zaufanym lappy, każda część łańcucha będzie zdolna do uwierzytelnienia.

Korzyści z połączeń przekierowanych

Przekierowanie uwierzytelniania oferuje wiele korzyści nie omawianych w tym artykule. Aby przekonać mnie do ważności agenta przekierowania, Charles Karney podzielił się ze mną informacją o tych trzech korzyściach:

  1. Klucz prywatny jest przechowywany jedynie na zaufanej maszynie. Chroni to przed złośliwymi użytkownikami, którzy zbierają zaszyfrowane klucze, a następnie próbują złamać szyfr.
  2. Ssh-agent jest uruchomiony na zaufanym systemie. To z kolei chroni przed intruzami, którzy robią zrzut pamięci procesu agenta i wyciągają z niego odszyfrowany klucz prywatny.
  3. Odkąd jedynym wymogiem jest wpisanie hasła na zaufanym hoście, można wykluczyć logowanie naciśnięć klawiszy i uzyskania tego hasła przez osoby niepowołane.

Jedynym minusem tego rozwiązania jest to, że nie rozwiązuje ono problemu z wykonaniem prac cron'a. Jedynym wyjściem wtedy jest wymuszenie od wszystkich prac uwierzytelnienia. Jeśli to konieczne, prace te mogą użyć ssh aby na zdalnym systemie stworzyć kopie zapasowe, zsynchronizować wszystkie pliki i tym podobne.

Teraz, skoro poznaliśmy już agenta przesyłającego uwierzytelnienie połączenia, wróćmy do ostatnich unowocześnień w samym skrypcie keychain.

Unowocześnienia skryptu keychain i jego funkcjonalność

Dzięki łatkom nadesłanym przez użytkowników, zostało wprowadzonych wiele znaczących zmian. Kilka łatek znalazło powiązania z funkcjami. Dla przykładu: przypomnijmy sobie, że keychain tworzył plik ~/.ssh-agent; nazwa tego pliku została zmieniona na ~/.ssh-agent-[hostname], przez co keychain działa z NFS, zamontowanym w katalogach domowych, dzięki czemu dostęp do niego możliwy jest z wielu hostów. W dodatku, plik ~/.ssh-agent-[hostname] jest teraz plikiem ~/.ssh-agent-csh-[hostname], przez co może zostać wykorzystany przez kompatybilne z csh powłoki. Została również dodana nowa opcja --nocolor, dzięki czemu w razie potrzeby kolorowanie może zostać wyłączone

Poprawa kompatybilności z powłokami

Podczas gdy funkcjonalność unowocześnień została poprawiona, głównym problemem stał się brak współpracy z powłokami. Wiemy, że keychain w wersji 1.0 wymagał powłoki bash. Jego późniejsze wersje zostały zmienione tak, aby były kompatybilne z wszystkimi rodzajami powłok. Ta zmiana zezwoliła keychain pracować "poza maszyną" na każdym systemie Uniksowym, włączając Linux, BSD, Solaris, IRIX oraz AIX. Przejście na sh i generalnie współpraca z UNIX była nie lada wyzwaniem i olbrzymim doświadczeniem. Stworzenie zwykłego skryptu, który może zostać wykonany na każdej z tych platworm było dosyć skomplikowane. Przede wszystkim dlatego, że nie mam dostępu do tych wszystkich systemów. Na szczęście jednak, cała masa użytkowników na całym globie ma, a wielu z nich udzieliło wspaniałego wsparcia w rozwiązywaniu problemów.

Były dwa rodzaje probemów kompatybilności, które musiały zostać naprawione. Przede wszystkim, musiałem być pewny, że keychain używa jedynie wbudowanych w siebie wyrażeń i operatorów, które są w pełni wspierane przez wszystkie powłoki, włączając popularne darmowe i komercjalne UNIX sh, zsh oraz bash w wersjach 1 i 2. Tu jest kilka wprowadzonych przez użytkowników poprawek, które włączyliśmy do kodu keychain:

W starszych wersjach powłok nie można użyć ~ w odniesieniu do katalogu domowego. Dlatego zamiast tego został wprowadzony $HOME:

Listing 1.3: Tworzenie $HOME

hostname=`uname -n`
pidf=${HOME}/.ssh-agent-${hostname}
cshpidf=${HOME}/.ssh-agent-csh-${hostname}

Następnie wszystkie wzmianki o source zostały zmienione na . aby mieć pewność, że będzie współpracował z /bin/sh w NetBSD:

Listing 1.4: Współpraca z NetBSD

if [ -f $pidf ]
then
    . $pidf
else
SSH_AGENT_PID="NULL"
fi

Z czasem zastosowałem również kilka innych poprawek. Jeden bystry autor skryptów poinformował mnie, że zamiast tworzenia plików poprzez "touch", można go stworzyć wpisując samą jego nazwę:

Listing 1.5: Tworzenie plików

> foo

Polegając na składni powłoki bardziej niż na postaci binarnej, unikamy funkcji fork(), więc skrypty stają się odrobinę bardziej wydajne. Polecenie > foo powinno działać z każdą powłoką. Wygląda jednak na to, że nie jest wspierane przez ash. Nie powinno to jednak stanowić problemu dla większości użytkowników odkąd ash jest używany bardziej w sytuacjach awaryjnych jak w codziennej pracy.

Problemy wykonywalności platform

Stworzenie skryptu działającego na różnorakich, unikso-podobnych systemach, wymaga więcej niż jedynie zastosowanie ubogiej składni sh. Należy pamiętać, że większość skryptów wywołuje zewnętrzne polecenia, takie jak grep, awk, ps i inne. Komendy te muszą być wywołane w zgodny z wszelkimi standardami sposób. Dla przykładu, polecenie echo w większości systemów z rodziny UNIX rozpoznaje opcję -e, podczas gdy Solaris jej nie rozpoznaje -- drukuje ją tak, jak zwykły tekst. Zatem, aby keychain współpracował w tym wypadku z Solaris'em, potrzeba:

Listing 1.6: Przechytrzanie Solaris'a

if [ -z "`echo -e`" ]
then
    E="-e"
fi

Według powyższego skryptu, zmienna E jest równa -e, jeśli opcja -e jest wspierana. Wtedy polecenie echo może być wywołane w następujący sposób:

Listing 1.7: Lepsze echo

echo $E Usage: ${CYAN}${0}${OFF} [ ${GREEN}options${OFF} ] ${CYAN}sshkey${OFF} ...

Używając echo $E zamiast echo -e, jest możliwe wyłączenie opcji -e w razie potrzeby.

pidof, ps

Prawdopodobnie najbardziej znaczącą poprawką w kompatybilności keychain była zmiana, dzięki której program wykrywa proces uruchomionego ssh-agent. Wcześniej używałem do tego celu komendy pidof, którą musiałem zastąpić, ponieważ na wielu systemach nie jest dostępna. Szczerze mówiąc, pidof nie jest najlepszym roziązaniem, ponieważ wyświetla wszystkie uruchomione w systemie procesy ssh-agent, podczas gdy my jesteśmy zainteresowani procesami przypisanymi do danego użytkownika.

Zatem zamiast posługiwać się komendą pidof, przefiltrowaliśmy wyjście polecenia ps, przez grep i awk. Była to jedna z opcji zgłoszonych przez użytkowników:

Listing 1.8: Potok lepszy niż pidof

mypids=`ps uxw | grep ssh-agent | grep -v grep | awk '{print $2}'`

Powyższy potok przyrówna zmienną mypids do wartości każdego procesu ssh-agent, którego właścicielem jest dany użytkownik. Komenda grep -v grep jest użyta, by proces naszego potoku nie stał się częścią listy PID.

Metoda ta jest dobra w zamyśle. W praktyce nie wygląda to dokładnie w ten sposób. Dla przykładu: polecenie ps uxw działa na systemie Linux, ale już nie działa na systemie IRIX, a polecenie ps -u username -f działa pod Linuksem, IRIX-em i Solaris'em, lecz nie pod BSD. Aby obejść tego typu problem, keychain, zanim wykona potok, sam wykrywa czy systemowe ps działa ze składnią BSD lub SysV:

Listing 1.9: Wykrycie BSD lub System V

psopts="FAIL"
ps uxw >/dev/null 2>&1
if [ $? -eq 0 ]
then
psopts="uxw"
else
ps -u `whoami` -f >/dev/null 2>&1
if [ $? -eq 0 ]
then
psopts="-u `whoami` -f"
fi
fi
if [ "$psopts" = "FAIL" ]
then
echo $0: unable to use \"ps\" to scan for ssh-agent processes.
Report KeyChain version and echo system configuration to drobbins@gentoo.org.
exit 1
fi

mypids=`ps $psopts 2>/dev/null | grep "[s]sh-agent" | awk '{print $2}'` > /dev/null 2>&1

Aby upewnić się, że pracujemy z należącą do BSD lub System V składnią polecenia ps, skrypt wykonuje "przebieg próbny": sprawdza dane wyjściowe ps uxw. Jeśli kod błędu jest równy zero, wiemy, że ps uxw działa, a my możemy odpowiednio ustawić opcje komendy ps. Natomiast, jeśli ps uxw zwróci kod błędu różny od zera (wskazując na pracę z opcjami rodem BSD), wykonujemy następny przebieg próbny poleceniem ps -u `whoami` -f; kolejny raz uzyskujemy dane wyjściowe. W tym momencie znaleźliśmy jeden z dwóch wariantów opcji dla ps. Jeśli staje się inaczej, widzimy błąd, a praca zostaje zakończona. Jednak jest wysoce prawdopodobne, że jedna z dwóch komend zadziała, a zatem wykonamy powyższy fragment kodu -- potok ps.

Potok zawiera również "perełkę", którą uprzejmie nadesłał do mnie Hans Peter Verne. Należy zauważyć, że człon grep -v grep nie jest już częścią potoku; został on usunięty, a grep "ssh-agent" został nadpisany przez grep "[s]sh-agent". Ta prosta komenda kończy swoją pracę w tym samym punkcie, co grep ssh-agent | grep -v grep.

Listing 1.10: Doskonała sztuczka z grep

mypids=`ps $psopts 2>/dev/null | grep "[s]sh-agent" | awk '{print $2}'` > /dev/null 2>&1

Nie prawda, że zdumiewające? Jeśli stwierdzasz, że grep "ssh-agent" oraz grep "[s]sh-agent" zwrócą identyczne dane wyjściowe, masz rację. Ale dlaczego generują różne wyniki? Oto jak to działa: używając grep "[s]sh-agent" zmienia się wynik polecenia grep w liście procesów wyświetlonych po ps. Ponieważ ciąg "[s]sh-agent" nie jest równoznaczny z wyrażeniem regularnym "[s]sh-agent", grep nie zwraca własnego procesu. Jeśli wciąż nie potrafisz zrozumieć zasady działania, pobaw się jakiś czas programem grep. Jestem pewien, że do tego dojdziesz szybko.

Wniosek

Ta kolumna kończy moje sprawozdanie o OpenSSH. Dowiedziałeś się sporo, więc możesz zacząć używać OpenSSH do zabezpieczenia swojego systemu. W następnych miesiącach, podobny wątek zostanie kontunuowany serią "Przewodnik po zaawansowanych narzędziach systemów plików"

2.  Źródła



Drukuj

Zaktualizowano 21 października 2005

Podsumowanie: W trzeciej części Daniel Robbins pokaże jak użyć agenta OpenSSH, w celu poprawienia bezpieczeństwa. Podzieli sie również ostatnimi nowościami i ulepszeniami w skrypcie keychain.

Daniel Robbins
Autor

Dawid Węgliński
Tłumaczenie

Donate to support our development efforts.

Support OSL
Gentoo Centric Hosting: vr.org
Tek Alchemy
SevenL.net
Global Netoptex Inc.
Bytemark
Online Kredit Index
Copyright 2001-2009 Gentoo Foundation, Inc. Questions, Comments? Contact us.