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.