Uruchom ssh-agent przy logowaniu


262

Mam witrynę jako zdalne repozytorium Git pobierające z Bitbucket.com przy użyciu aliasu SSH. Mogę ręcznie uruchomić agenta ssh na moim serwerze, ale muszę to robić przy każdym logowaniu przez SSH.

Ręcznie uruchamiam agenta ssh:

eval ssh-agent $SHELL

Następnie dodaję agenta:

ssh-add ~/.ssh/bitbucket_id

Następnie pojawia się, gdy:

ssh-add -l

I dobrze mi idzie. Czy istnieje sposób na zautomatyzowanie tego procesu, więc nie muszę tego robić przy każdym logowaniu? Na serwerze działa RedHat 6.2 (Santiago).


2
Wszystko, co chcesz zrobić przy każdym logowaniu, powinno mieć postać .profile (logowanie na terminalu) lub .xinitrc (dla logowania GUI).
Barmar

1
Ach! Używałem .bash_profile ... Jaka jest różnica między .profile i .bash_profile?
Pathsofdesign 18.09.2013

1
Nie jestem pewien, dlaczego uruchamiasz polecenie w ten sposób. ssh-agent <command>działa <command>jako podproces ssh-agent, więc zaczynasz nową powłokę. Myślę, że chcesz eval ssh-agent.
Barmar

9
.bash_profilejest specyficzny dla bash, .profilejest ogólny dla wszystkich powłok POSIX. bashnajpierw szuka .bash_profile, a następnie domyślnie .profile.
Barmar

5
Prawidłowym sposobem na odrodzenie się ssh-agentdla „standardowej” powłoki (zgodnej z POSIX) jest eval $(ssh-agent -s). Należy również zauważyć, że trzeba upewnić się, że prawidłowo pozbyć się agenta, gdy użytkownik loguje się, więc jest to również wskazane, aby umieścić trap 'kill $SSH_AGENT_PID' EXITw twojej .profilepo linii, która zaczyna agenta.
kostix

Odpowiedzi:


368

Przejrzyj ten artykuł. Może ci się to bardzo przydać:

http://mah.everybody.org/docs/ssh

Na wypadek, gdyby powyższy link zniknął pewnego dnia, przechwytuję główny fragment poniższego rozwiązania:

To rozwiązanie Josepha M. Reagle'a za pośrednictwem Daniela Starina:

Dodaj to do swojego .bash_profile

SSH_ENV="$HOME/.ssh/agent-environment"

function start_agent {
    echo "Initialising new SSH agent..."
    /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
    echo succeeded
    chmod 600 "${SSH_ENV}"
    . "${SSH_ENV}" > /dev/null
    /usr/bin/ssh-add;
}

# Source SSH settings, if applicable

if [ -f "${SSH_ENV}" ]; then
    . "${SSH_ENV}" > /dev/null
    #ps ${SSH_AGENT_PID} doesn't work under cywgin
    ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
        start_agent;
    }
else
    start_agent;
fi

Ta wersja jest szczególnie przyjemna, ponieważ sprawdzi, czy już uruchomiłeś ssh-agent, a jeśli nie będzie w stanie go znaleźć, uruchomi go i zapisze ustawienia, aby można je było użyć przy następnym uruchomieniu muszla.


8
Ponowne uruchomienie komputera nie jest konieczne. Możesz po prostu ponownie załadować, .bash_profileużywając source ~/.bash_profilew bieżącej sesji powłoki. Ponowne uruchomienie komputera będzie również działać, ponieważ i tak załaduje nową konfigurację.
Lakmus

11
Użyj SSH_ENV="$HOME/.ssh/env"(tj. Po prostu nie / środowiska) Dlaczego? sshd używa ~ / .ssh / environment (patrz strona podręcznika man: PermitUserEnvironment). Github również poleca to w swoim rozwiązaniu - help.github.com/articles/…
Andrew Murphy,

7
Ten skrypt działał dla mnie, gdy umieściłem go w moim pliku ~ / .bashrc (nie w moim ~ / .profile lub ~ / .bash_profile). Gdy po raz pierwszy otwieram konsolę lokalną, wyświetla monit o podanie hasła, wszystko działa od tego momentu bez dalszych monitów. Twoje zdrowie.
andrew pate

3
Dodanie ssh-agentpolecenia start w .bashrc spowoduje, że scppolecenie nie będzie działać.
Dzanvu,

5
Wciąż denerwujące ... musisz to robić przy każdym logowaniu ... nawet jeśli nie używasz ssh. Musisz rozpalić ten ogień za każdym razem, gdy wywoływany jest ssh ... i idealnie, powinieneś być w stanie skonfigurować, które hosty powodują ładowanie kluczy.
Erik Aronesty

97

W Arch Linux następujące działania działają naprawdę świetnie (powinny działać na wszystkich dystrybucjach systemowych):

Utwórz usystematyzowaną usługę użytkownika, umieszczając następujące elementy w ~/.config/systemd/user/ssh-agent.service:

[Unit]
Description=SSH key agent

[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK

[Install]
WantedBy=default.target

Skonfiguruj powłokę, aby mieć zmienną środowiskową dla gniazda ( .bash_profile, .zshrc, ...):

export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"

Włącz usługę, aby została uruchomiona automatycznie podczas logowania i uruchom ją:

systemctl --user enable ssh-agent
systemctl --user start ssh-agent

Dodaj następujące ustawienie konfiguracji do lokalnego pliku konfiguracyjnego ssh ~/.ssh/config(działa od wersji SSH 7.2):

AddKeysToAgent  yes

To poinstruuje klienta ssh, aby zawsze dodawał klucz do działającego agenta, więc nie ma potrzeby wcześniejszego dodawania go.


3
Znalazłem ten komentarz, próbując to zrobić w Ubuntu. Wydaje się, że gra znacznie ładniej z wbudowanymi systemami niż włamywanie się do skryptów startowych, przynajmniej biorąc pod uwagę moją wiedzę o tym, jak system powinien działać.
xiterion

Próbowałem tego na Ubuntu 16.04 LTS. Niestety, każdy proces powłoki wymaga indywidualnego ssh-agentprocesu. Być może brakuje mi wiedzy nawet po przeczytaniu dokumentacji.
Daisuke Aramaki,

Możesz także użyć Type = simple . wiki.archlinux.org/index.php/…
Hans-J. Schmid

2
więc czy to rozwiązanie w zasadzie instaluje / konfiguruje usługę systemową (ale tylko dla użytkownika)?
Trevor Boyd Smith

Nie spowoduje to jednak ustawienia SSH_AGENT_PIDzmiennej środowiskowej :(
MrMeszaros

73

Stare pytanie, ale natrafiłem na podobną sytuację. Nie sądzę, że powyższa odpowiedź w pełni spełnia wymagania. Brakującym elementem jest keychain; zainstaluj, jeśli jeszcze nie jest.

sudo apt-get install keychain

Następnie dodaj następujący wiersz do swojego ~/.bashrc

eval $(keychain --eval id_rsa)

Spowoduje to uruchomienie, ssh-agentjeśli nie jest uruchomione, połączenie się z nim, jeśli tak, załadowanie ssh-agentzmiennych środowiskowych do powłoki i załadowanie klucza ssh.

Zmień id_rsana dowolny klucz prywatny, ~/.sshktóry chcesz załadować.

Odniesienie

/unix/90853/how-can-i-run-ssh-add-automatically-without-password-prompt


brelok nie działa dla mnie zgodnie z podanymi instrukcjami. Dodałem do .bash_profile i ssh za każdym razem pyta o hasło. próbowałem wiele razy w tej samej powłoce. nie ma kości. wracając do podstawowego podejścia ssh-agent
javadba

Dodaj eval keychain --eval id_[yourid file]do .bashrc
xelber

4
Spędziłem 20 minut szukając rozwiązania ze względu na formatowanie komentarzy StackOverflow. Za komentarz xelber w powyższym prawidłowe rozwiązanie jest eval `keychain --eval id_[yourid file]`do .bashrc. Wsteczki wymagane do oceny zmiennych środowiskowych w bieżącej powłoce w celu uzyskania dostępu do działającego agenta ssh.
James

2
To jest prawidłowe i proste rozwiązanie. Jeśli nie chcesz wyświetlać dziennika podczas wykonywania polecenia pęku kluczy, możesz dodać -qopcję trybu cichego. Więcej informacji o pęku kluczy: funtoo.org/Keychain
Diki Ananta

4
Dzięki, jest to zdecydowanie najbardziej eleganckie rozwiązanie.
greenspand

37

Przyjęte rozwiązanie ma następujące wady:

  • utrzymanie jest skomplikowane;
  • ocenia plik pamięci, który może prowadzić do błędów lub naruszeń bezpieczeństwa;
  • uruchamia agent, ale go nie zatrzymuje, co jest bliskie pozostawieniu kluczyka w stacyjce.

Jeśli twoje klucze nie wymagają wpisywania hasła, sugeruję następujące rozwiązanie. Dodaj na .bash_profile samym końcu (edytuj listę kluczy do swoich potrzeb):

exec ssh-agent $BASH -s 10<&0 << EOF
    ssh-add ~/.ssh/your_key1.rsa \
            ~/.ssh/your_key2.rsa &> /dev/null
    exec $BASH <&10-
EOF

Ma następujące zalety:

  • znacznie prostsze rozwiązanie;
  • sesja agenta kończy się po zakończeniu sesji bash.

Ma możliwe wady:

  • interaktywny ssh-add polecenie wpłynie tylko na jedną sesję, co w rzeczywistości jest problemem tylko w bardzo nietypowych okolicznościach;
  • bezużyteczne, jeśli wymagane jest wpisanie hasła;
  • uruchomiona powłoka staje się niezalogowana (co nie ma wpływu na AFAIK).

Zauważ, że kilka ssh-agentprocesów nie jest wadą, ponieważ nie zajmują więcej pamięci ani czasu procesora.


Mam klucze SSH w katalogu poza $ HOME w Windows 10, używając Git Bash. Zmiana ścieżki do RSA była wszystkim, co musiałem zrobić, aby to zadziałało. TYVM!
kayleeFrye_onDeck

7
Argumentowałbym, że „Jeśli twoje klucze nie wymagają wpisywania hasła”, jest to prawie równoważne z pozostawieniem kluczyka w stacyjce.
Bruno Bronosky

Przynajmniej jest na twoim hoście, a nie gdzieś w sieci.
midenok

1
„Argumentowałbym, że„ Jeśli klucze nie wymagają wpisywania hasła ”, jest to bliskie pozostawieniu kluczyka w stacyjce.” <- Wyjaśnij, jak to zrobić? Ponieważ klucze są znacznie bardziej elastyczne niż hasła, znacznie łatwiej je odwołać (co? Używasz kluczy tylko dla użytkowników sudo z pełnym dostępem? Tsk tsk). Wiele zestawów kluczy dla wielu profili użytkowników. Jeśli chcesz coś zautomatyzować (np. Wdrożenie lub kontrole od końca do końca), powodzenia w ciągłym wpisywaniu haseł podczas „aranżacji”.
Scott Prive,

2
Nie rób tego Klucze bez hasła to zła praktyka.
user48678,

26

Dodaj to do swojego ~/.bashrc, a następnie wyloguj się i zaloguj ponownie, aby zastosować.

if [ ! -S ~/.ssh/ssh_auth_sock ]; then
  eval `ssh-agent`
  ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
ssh-add -l > /dev/null || ssh-add

Powinno to monitować o podanie hasła tylko przy pierwszym logowaniu po każdym ponownym uruchomieniu. Będzie używać tego samego ssh-agenttak długo, jak długo będzie działać.


Czego byśmy użyli zamiast tego, gdybyśmy mieli wiele kluczy i nie byliby nazwani ~/.ssh/id_rsa? Wygląda na to, że ssh-addczęść twojej odpowiedzi oczekuje domyślnych nazw plików dla kluczy.
Gabriel Staples

Tak. Wierzę, że w razie potrzeby możesz po prostu dodać nazwy plików na samym końcu ostatniego wiersza
Collin Anderson

Ale nadal nie możesz zautomatyzować skryptu, na przykład ściągać polecenia git bez ręcznego wprowadzania hasła? Jak tego uniknąć?
Trainoasis

7

Używałem więc opisanych powyżej podejść, ale wolę, aby agent umarł po zakończeniu mojej ostatniej sesji bash. Jest to nieco dłużej niż w przypadku innych rozwiązań, ale to moje preferowane podejście. Podstawową ideą jest to, że pierwsza sesja bash uruchamia agenta ssh. Następnie każda dodatkowa sesja bash sprawdza plik konfiguracyjny ( ~/.ssh/.agent_env). Jeśli tak jest i jest uruchomiona sesja, wówczas /tmpnależy pobrać środowisko i utworzyć dowiązanie twarde do pliku gniazda w (musi znajdować się w tym samym systemie plików, co oryginalny plik gniazda). Po zamknięciu sesji bash każda usuwa swój własny link twardy. W ostatniej sesji do zamknięcia okaże się, że hardlinki mają 2 linki (hardlink i oryginał), usunięcie własnego gniazda procesów i zabicie procesu spowoduje 0, pozostawiając czyste środowisko po zamknięciu ostatniej sesji bash.

# Start ssh-agent to keep you logged in with keys, use `ssh-add` to log in
agent=`pgrep ssh-agent -u $USER` # get only your agents           
if [[ "$agent" == "" || ! -e ~/.ssh/.agent_env ]]; then
    # if no agents or environment file is missing create a new one
    # remove old agents / environment variable files
    kill $agent running
    rm ~/.ssh/.agent_env 

    # restart
    eval `ssh-agent` 
    echo 'export SSH_AUTH_SOCK'=$SSH_AUTH_SOCK >> ~/.ssh/.agent_env             
    echo 'export SSH_AGENT_PID'=$SSH_AGENT_PID >> ~/.ssh/.agent_env             
fi

# create our own hardlink to the socket (with random name)           
source ~/.ssh/.agent_env                                                    
MYSOCK=/tmp/ssh_agent.${RANDOM}.sock                                        
ln -T $SSH_AUTH_SOCK $MYSOCK                                                
export SSH_AUTH_SOCK=$MYSOCK                                                

end_agent()                                                                     
{
    # if we are the last holder of a hardlink, then kill the agent
    nhard=`ls -l $SSH_AUTH_SOCK | awk '{print $2}'`                             
    if [[ "$nhard" -eq 2 ]]; then                                               
        rm ~/.ssh/.agent_env                                                    
        ssh-agent -k                                                            
    fi                                                                          
    rm $SSH_AUTH_SOCK                                                           
}                                                                               
trap end_agent EXIT                                                             
set +x              

jeśli uruchomimy to jako skrypt BASH przy logowaniu do jakiejkolwiek innej powłoki (innej niż BASH), to też powinno działać, prawda?
hoijui

7

Aby dodać jeszcze jedno rozwiązanie: P, wybrałem kombinację rozwiązań @spheenik i @ collin-anderson.

 # Ensure that we have an ssh config with AddKeysToAgent set to true
 if [ ! -f ~/.ssh/config ] || ! cat ~/.ssh/config | grep AddKeysToAgent | grep yes > /dev/null; then
     echo "AddKeysToAgent  yes" >> ~/.ssh/config
 fi
 # Ensure a ssh-agent is running so you only have to enter keys once
 if [ ! -S ~/.ssh/ssh_auth_sock ]; then
   eval `ssh-agent`
   ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
 fi
 export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock

Może być trochę bardziej elegancki, ale jest prosty i czytelny. To rozwiązanie:

  • zapewnia, że AddKeysToAgent yesjest w konfiguracji ssh, więc klucze zostaną automatycznie dodane po użyciu
  • nie monituje o podanie żadnych haseł podczas logowania (ponownie, jednorazowe wprowadzenie hasła występuje przy pierwszym użyciu)
  • dyskretnie uruchamia agenta ssh, jeśli jeszcze go nie uruchomił

Komentarze mile widziane :)


1
To działało idealnie dla mnie. Na Kubuntu umieściłem go w .profile.
Shai

1
Dobrze wiedzieć o AddKeysToAgent yesustawieniu. Dzięki.
Collin Anderson

3

Rozwiązałem to, dodając to do / etc / profile - w całym systemie (lub do lokalnego pliku .profile użytkownika lub _.bash_profile_):

# SSH-AGENT 
#!/usr/bin/env bash
SERVICE='ssh-agent'
WHOAMI=`who am i |awk '{print $1}'`

if pgrep -u $WHOAMI $SERVICE >/dev/null
then
    echo $SERVICE running.
else
    echo $SERVICE not running.
    echo starting
    ssh-agent > ~/.ssh/agent_env
fi
. ~/.ssh/agent_env

Spowoduje to uruchomienie nowego agenta ssh-agent, jeśli nie jest uruchomiony dla bieżącego użytkownika, lub ponowne ustawienie parametru env ssh-agent, jeśli jest uruchomiony.


Dziękujemy za poinformowanie, czy agent już działa!
Mike Maxwell

Jak if pgrep -u $WHOAMI $SERVICE >/dev/nulldziała
Josh Desmond

3

Użytkownicy skorupy ryb mogą użyć tego skryptu, aby zrobić to samo.

# content has to be in .config/fish/config.fish
# if it does not exist, create the file
setenv SSH_ENV $HOME/.ssh/environment

function start_agent                                                                                                                                                                    
    echo "Initializing new SSH agent ..."
    ssh-agent -c | sed 's/^echo/#echo/' > $SSH_ENV
    echo "succeeded"
    chmod 600 $SSH_ENV 
    . $SSH_ENV > /dev/null
    ssh-add
end

function test_identities                                                                                                                                                                
    ssh-add -l | grep "The agent has no identities" > /dev/null
    if [ $status -eq 0 ]
        ssh-add
        if [ $status -eq 2 ]
            start_agent
        end
    end
end

if [ -n "$SSH_AGENT_PID" ] 
    ps -ef | grep $SSH_AGENT_PID | grep ssh-agent > /dev/null
    if [ $status -eq 0 ]
        test_identities
    end  
else
    if [ -f $SSH_ENV ]
        . $SSH_ENV > /dev/null
    end  
    ps -ef | grep $SSH_AGENT_PID | grep -v grep | grep ssh-agent > /dev/null
    if [ $status -eq 0 ]
        test_identities
    else 
        start_agent
    end  
end

2

Używam do tego narzędzia ssh-ident .

Z jego strony man :

ssh-ident - Uruchom i użyj ssh-agent i załaduj tożsamości w razie potrzeby.


1

Wypróbowałem kilka rozwiązań z wielu źródeł, ale wszystkie wydawały się zbyt wielkim problemem. Wreszcie znalazłem najłatwiejszy :)

Jeśli nie znasz jeszcze zsh i oh-my-zsh zainstaluj go. Będzie Ci się podobało :)

Następnie edytuj .zshrc

vim ~/.zshrc

znajdź pluginssekcję i zaktualizuj ją, aby użyć w następujący ssh-agentsposób:

plugins=(ssh-agent git)

I to wszystko! Będziesz ssh-agentdziałał przy każdym uruchomieniu powłoki


1

Bardzo lubię twoje odpowiedzi. cygwin / linuxUłatwiło to pracę z hostami. Połączyłem funkcje początkowe i końcowe, aby zapewnić bezpieczeństwo.

SSH_ENV="$HOME/.ssh/.agent_env"

function start_agent {
    echo "Initialising new SSH agent..."

    eval `/usr/bin/ssh-agent`
    echo 'export SSH_AUTH_SOCK'=$SSH_AUTH_SOCK >> ${SSH_ENV}
    echo 'export SSH_AGENT_PID'=$SSH_AGENT_PID >> ${SSH_ENV}

    echo succeeded
    chmod 600 "${SSH_ENV}"
    . "${SSH_ENV}" > /dev/null
    /usr/bin/ssh-add;
}

# Source SSH settings, if applicable
if [ -f "${SSH_ENV}" ]; then
    . "${SSH_ENV}" > /dev/null
    #ps ${SSH_AGENT_PID} doesn't work under cywgin
    ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
        start_agent;
    }
else
    start_agent;
fi

# create our own hardlink to the socket (with random name)
MYSOCK=/tmp/ssh_agent.${RANDOM}.sock
ln -T $SSH_AUTH_SOCK $MYSOCK
export SSH_AUTH_SOCK=$MYSOCK

end_agent()
{
    # if we are the last holder of a hardlink, then kill the agent
    nhard=`ls -l $SSH_AUTH_SOCK | awk '{print $2}'`
    if [[ "$nhard" -eq 2 ]]; then
        rm ${SSH_ENV}
        /usr/bin/ssh-agent -k
    fi
    rm $SSH_AUTH_SOCK
}
trap end_agent EXIT
set +x
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.