Inicie ssh-agent al iniciar sesión


262

Tengo un sitio como un repositorio Git remoto desde Bitbucket.com usando un alias SSH. Puedo iniciar manualmente el agente ssh en mi servidor, pero tengo que hacerlo cada vez que inicio sesión a través de SSH.

Inicio manualmente el agente ssh:

eval ssh-agent $SHELL

Luego agrego el agente:

ssh-add ~/.ssh/bitbucket_id

Luego aparece cuando hago:

ssh-add -l

Y estoy listo para irme. ¿Hay alguna forma de automatizar este proceso para que no tenga que hacerlo cada vez que inicio sesión? El servidor ejecuta RedHat 6.2 (Santiago).


2
Todo lo que desee hacer cada vez que inicie sesión debe estar en .profile (inicios de sesión de terminal) o .xinitrc (para inicios de sesión de GUI).
Barmar

1
Ah! Estaba usando .bash_profile ... ¿Cuál es la diferencia entre .profile y .bash_profile?
Pathsofdesign

1
No estoy seguro de por qué estás ejecutando el comando de esa manera en primer lugar. ssh-agent <command>se ejecuta <command>como un subproceso de ssh-agent, por lo que está comenzando un nuevo shell. Creo que quieres eval ssh-agent.
Barmar

9
.bash_profilees específico de bash, .profilees genérico para todos los shells POSIX. bashbuscará primero .bash_profile, y luego por defecto a .profile.
Barmar

55
La forma correcta de generar ssh-agentun shell "estándar" (compatible con POSIX) es eval $(ssh-agent -s). Tenga en cuenta también que usted tiene que asegurarse de que correctamente deshacerse del agente al cerrar la sesión, por lo que también es recomendable poner trap 'kill $SSH_AGENT_PID' EXITen su .profiledespués de la línea que se inicia el agente.
kostix

Respuestas:


368

Por favor, lea este artículo. Puede encontrar esto muy útil:

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

En caso de que el enlace anterior desaparezca algún día, estoy capturando la pieza principal de la solución a continuación:

Esta solución de Joseph M. Reagle a través de Daniel Starin:

Agregue este siguiente a su .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

Esta versión es especialmente buena, ya que verá si ya ha iniciado ssh-agent y, si no puede encontrarla, la iniciará y almacenará la configuración para que pueda usarla la próxima vez que inicie un cáscara.


8
El reinicio de la máquina no es necesario. Puede recargar .bash_profileusando source ~/.bash_profilesu sesión de shell actual. El reinicio de la máquina también funcionará porque eso cargará la nueva configuración de todos modos.
tornasol

11
Uso SSH_ENV="$HOME/.ssh/env"(es decir, no / entorno) ¿Por qué? sshd usa ~ / .ssh / environment (consulte la página de manual: PermitUserEnvironment). Github también recomienda esto en su solución - help.github.com/articles/…
Andrew Murphy

77
Este script funcionó para mí cuando lo puse en mi archivo ~ / .bashrc (no en mi ~ / .profile o ~ / .bash_profile). La primera vez que abro una consola local solicita la frase de contraseña, todo funciona a partir de ese momento sin más indicaciones. Salud.
Andrew Paté

3
Agregar el ssh-agentcomando de inicio en .bashrc hará que el scpcomando no funcione.
Dzanvu

55
Todavía molesto ... tienes que hacer esto cada vez que inicies sesión ... incluso si no usas ssh. Es necesario que esto se active cada vez que se llama a ssh ... e idealmente, debería poder configurar qué hosts causan qué claves cargar.
Erik Aronesty

99

En Arch Linux, lo siguiente funciona realmente bien (debería funcionar en todas las distribuciones basadas en systemd):

Cree un servicio de usuario systemd, poniendo lo siguiente para ~/.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

Configure el shell para tener una variable de entorno para el socket ( .bash_profile, .zshrc, ...):

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

Habilite el servicio para que se inicie automáticamente al iniciar sesión e inícielo:

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

Agregue la siguiente configuración a su archivo de configuración ssh local ~/.ssh/config(esto funciona desde SSH 7.2):

AddKeysToAgent  yes

Esto le indicará al cliente ssh que siempre agregue la clave a un agente en ejecución, por lo que no es necesario agregar ssh de antemano.


3
Encontré este comentario al intentar hacer esto en Ubuntu. Parece jugar mucho mejor con los sistemas integrados que piratear algo en los scripts de inicio, al menos dado mi conocimiento de cómo debería funcionar el sistema.
xiterion

Intenté esto en Ubuntu 16.04 LTS. Desafortunadamente, cada proceso de shell quiere su ssh-agentproceso individual . Tal vez me falta conocimiento incluso después de leer los documentos.
Daisuke Aramaki

También puede usar Type = simple . wiki.archlinux.org/index.php/…
Hans-J. Schmid

2
Entonces, ¿esta solución básicamente está instalando / configurando un servicio systemd (pero solo para el usuario)?
Trevor Boyd Smith

Sin SSH_AGENT_PIDembargo, esto no establecerá la variable de entorno :(
MrMeszaros

73

Antigua pregunta, pero me encontré con una situación similar. No piense que la respuesta anterior logra completamente lo que se necesita. La pieza que falta es keychain; instálalo si aún no lo está.

sudo apt-get install keychain

Luego agregue la siguiente línea a su ~/.bashrc

eval $(keychain --eval id_rsa)

Esto iniciará ssh-agentsi no se está ejecutando, conéctese a él si es así, cargue las ssh-agentvariables de entorno en su shell y cargue su clave ssh.

Cambie id_rsaa la clave privada ~/.sshque desee cargar.

Referencia

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


El llavero no funciona para mí según las instrucciones dadas. Agregué a .bash_profile y ssh todavía pide contraseña cada vez. Lo intenté varias veces en el mismo shell. no dados. volviendo al enfoque básico de agente ssh
javadba

Agregue eval keychain --eval id_[yourid file]a .bashrc
xelber el

44
Pasé 20 minutos investigando una solución debido al formato de comentarios de StackOverflow. Por el comentario de xelber anteriormente, la solución correcta es eval `keychain --eval id_[yourid file]`a .bashrc. Los backticks necesarios para evaluar las variables de entorno al shell actual para acceder al agente ssh en ejecución.
James

2
Esta es la solución correcta y simple. Si no desea ver el registro cuando se ejecuta el comando keychain, puede agregar la -qopción para el modo silencioso. Más información sobre Keychain: funtoo.org/Keychain
Diki Ananta

44
Gracias, esta es, con mucho, la solución más elegante.
Greenspand

37

La solución aceptada tiene los siguientes inconvenientes:

  • es complicado de mantener;
  • evalúa el archivo de almacenamiento que puede conducir a errores o brechas de seguridad;
  • inicia el agente pero no lo detiene, lo que equivale a dejar la llave en el encendido.

Si sus claves no requieren escribir contraseña, le sugiero la siguiente solución. Agregue lo siguiente a su .bash_profile final (edite la lista de claves según sus necesidades):

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

Tiene las siguientes ventajas:

  • solución mucho más simple;
  • la sesión del agente finaliza cuando finaliza la sesión bash.

Tiene posibles desventajas:

  • el ssh-addcomando interactivo influirá solo en una sesión, que de hecho es un problema solo en circunstancias muy atípicas;
  • inutilizable si se requiere escribir contraseña;
  • El shell iniciado se convierte en no inicio de sesión (lo que no influye en nada AFAIK).

Tenga en cuenta que varios ssh-agentprocesos no son una desventaja, ya que no requieren más memoria o tiempo de CPU.


Tengo claves SSH en un directorio fuera de $ HOME en Windows 10, usando Git Bash. Cambiar el camino hacia el RSA fue todo lo que necesitaba hacer para que esto funcionara. TYVM!
kayleeFrye_onDeck

77
Yo diría que "Si sus claves no requieren escribir contraseña" es equivalente a dejar la clave en el encendido.
Bruno Bronosky el

Al menos, está en su propio host, no en algún lugar de la red.
midenok

1
"Yo diría que" Si sus claves no requieren escribir la contraseña "es casi equivalente a dejar la clave en el encendido". <- ¿¿Explicar cómo? Debido a que las claves son mucho más flexibles que las contraseñas, mucho más fáciles de revocar (¿qué? ¿Solo está usando claves para usuarios de sudo con acceso completo? Tsk tsk). Múltiples conjuntos de claves para múltiples perfiles de usuarios. Si desea automatizar cualquier cosa (como la implementación o las comprobaciones de extremo a extremo), buena suerte constantemente escribiendo contraseñas durante la "orquestación".
Scott Prive

2
No hagas eso. Las claves sin contraseña son una mala práctica.
user48678

26

Agregue esto a su ~/.bashrc, luego cierre sesión y vuelva a entrar para que surta efecto.

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

Esto solo debe solicitar una contraseña la primera vez que inicie sesión después de cada reinicio. Continuará reutilizando lo mismo ssh-agentmientras siga ejecutándose.


¿Qué usaríamos en su lugar si tuviéramos varias claves y no se nombraran ~/.ssh/id_rsa? Parece que la ssh-addparte de su respuesta espera nombres de archivo predeterminados para las claves.
Gabriel Staples

Sip. Creo que puede agregar los nombres de archivo al final de la última línea si es necesario
Collin Anderson

Pero todavía no puede automatizar un script, ¿puede extraer cosas de git, por ejemplo, sin ingresar la contraseña manualmente? ¿Cómo evitar eso?
trainoasis

7

Así que solía usar los enfoques descritos anteriormente, pero prefiero que el agente muera cuando termine mi última sesión de bash. Esto es un poco más largo que las otras soluciones, pero es mi enfoque preferido. La idea básica es que la primera sesión de bash inicia el agente ssh. Luego, cada sesión bash adicional busca el archivo de configuración ( ~/.ssh/.agent_env). Si eso está allí y hay una sesión ejecutándose, obtenga el entorno y cree un enlace rígido al archivo socket /tmp(debe estar en el mismo sistema de archivos que el archivo socket original). A medida que las sesiones de bash se cierran, cada una elimina su propio enlace rígido. La última sesión para cerrar encontrará que los enlaces duros tienen 2 enlaces (el enlace duro y el original), la eliminación del propio socket del proceso y la eliminación del proceso dará como resultado 0, dejando un entorno limpio después del cierre de la última sesión de 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              

si ejecutamos esto como un script BASH al iniciar sesión en cualquier otro shell (que no sea BASH), también debería funcionar, ¿verdad?
hoijui

7

Solo para agregar otra solución: P, fui con una combinación de las soluciones de @spheenik y @ 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

Podría ser un poco más elegante, pero es simple y legible. Esta solución:

  • asegura AddKeysToAgent yes está en su configuración ssh, por lo que las claves se agregarán automáticamente al usarlas
  • no le pide que ingrese ninguna frase de contraseña al iniciar sesión (de nuevo, se ingresa una frase de contraseña una vez al primer uso)
  • inicia silenciosamente un agente ssh si aún no ha iniciado uno

Comentarios bienvenidos :)


1
Esto funcionó perfectamente para mí. En Kubuntu lo puse en .profile.
Shai

1
Es bueno saber sobre el AddKeysToAgent yesentorno. Gracias.
Collin Anderson

3

Lo resolví agregando esto al / etc / profile - en todo el sistema (o al usuario local .profile , o _.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

Esto inicia un nuevo ssh-agent si no se está ejecutando para el usuario actual, o restablece el parámetro ssh-agent env si se está ejecutando.


¡Gracias por decir cómo saber si el agente ya se está ejecutando!
Mike Maxwell el

¿Cómo funciona el if pgrep -u $WHOAMI $SERVICE >/dev/nulltrabajo?
Josh Desmond

3

Los usuarios de la concha de pescado pueden usar este script para hacer lo mismo.

# 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

Yo uso la herramienta ssh-ident para esto.

Desde su página de manual :

ssh-ident: inicia y usa ssh-agent y carga las identidades según sea necesario.


1

Intenté un par de soluciones de muchas fuentes, pero todas parecían demasiados problemas. Finalmente encontré el más fácil :)

Si aún no está familiarizado con zsh y oh-my-zsh , instálelo. Lo amarás :)

Luego edite .zshrc

vim ~/.zshrc

encuentre la pluginssección y actualícela para usarla ssh-agentasí:

plugins=(ssh-agent git)

¡Y eso es todo! Tendrá ssh-agenten funcionamiento cada vez que inicie su shell


1

Me gustan mucho tus respuestas. cygwin / linuxFacilitó mucho el trabajo desde los hosts. Combiné las funciones de inicio y fin para hacerlo seguro.

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.