Si decidimos poner la línea eval `ssh-agent`
en nuestro
~/.bash_profile
(véase .bash_profile vs .bashrc)
tenemos un problema: con cada sesión se lanza una nueva copia del agente ssh.
Es cierto que el asunto no es preocupante si sólo abrimos una o dos cónsolas, pero
si - como es mi caso - abrimos muchas en una sesión X tendremos que escribir la passphrase
bastantes veces. Un único agente debería ser suficiente.
Otro problema son las tareas automáticas que usan cron.
Las tareas arrancadas mediante cron
no heredan las variables de entorno
SSH_AUTH_SOCK
y SSH_AGENT_PID
y por tanto no saben
que proceso ssh-agent
deben contactar.
Es común ver que en ciertos Unix el arranque de la sesión X lleva aparejado el arranque de un agente SSH. Si ese es nuestro caso, tenemos la mayor parte del trabajo hecho. Por ejemplo en una configuración típica de Kubuntu vemos lo siguiente:
$ cat -n /etc/X11/Xsession.options 1 # $Id: Xsession.options 189 2005-06-11 00:04:27Z branden $ 2 # 3 # configuration options for /etc/X11/Xsession 4 # See Xsession.options(5) for an explanation of the available options. 5 allow-failsafe 6 allow-user-resources 7 allow-user-xsession 8 use-ssh-agent 9 use-session-dbus
La opción use-ssh-agent
hace que se dispare un agente en el momento
de arrancar las X. En efecto si vemos los procesos en el sistema
descubrimos la presencia de un agente:
casiano@europa:~$ ps -fA | grep agent casiano 6976 6911 0 10:57 ? 00:00:00 /usr/bin/ssh-agent x-session-manager casiano 8018 7625 0 11:07 pts/3 00:00:00 grep agentViendo las variables de entorno podemos ver el lugar en el que está el socket:
casiano@europa:~$ env | grep -i ssh SSH_AGENT_PID=6976 SSH_AUTH_SOCK=/tmp/ssh-qkuycC6911/agent.6911Podemos ver que el socket tiene los permisos puestos para que pueda ser accedida por el usuario que arrancó las X:
casiano@europa:~$ ls -ld /tmp/ssh-qkuycC6911/ drwx------ 2 casiano casiano 4096 2009-04-27 10:57 /tmp/ssh-qkuycC6911/ casiano@europa:~$ ls -l /tmp/ssh-qkuycC6911/ total 0 srw------- 1 casiano casiano 0 2009-04-27 10:57 agent.6911por tanto el usuario que arrancó las X puede acceder a ese agente. Veamos que claves están en ese agente:
rw------- 1 casiano casiano 0 2009-04-27 10:57 agent.6911 casiano@europa:~$ ssh-add -l 1024 49:4c:e1:b4:1a:ea:e6:73:fc:a1:e5:6b:54:c9:da:62 /home/casiano/.ssh/id_dsa (DSA)Ya esta la clave
/home/casiano/.ssh/id_dsa
.
Probablemente lo haya hecho en alguna prueba anterior.
Para empezar esta nueva prueba desde una situación inicial
vamos a suprimir todas las claves del agente.
casiano@europa:~$ ssh-add -D All identities removed.Si ahora intento conectarme a una máquina con esa clave, me es solicitada la passphrase:
casiano@europa:~$ ssh orion Enter passphrase for key '/home/casiano/.ssh/id_dsa': ^CInterrumpo la conexión pulsando CTRL-C y paso a añadir la clave al agente:
casiano@europa:~$ ssh-add /home/casiano/.ssh/id_dsa Enter passphrase for /home/casiano/.ssh/id_dsa: Identity added: /home/casiano/.ssh/id_dsa (/home/casiano/.ssh/id_dsa)Ahora puedo hacer la conexión sin necesidad de introducir la passphrase:
casiano@europa:~$ ssh orion Linux orion 2.6.8-2-686 #1 Tue Aug 16 13:22:48 UTC 2005 i686 GNU/Linux
Una solución parcial es arrancar el agente tan pronto como se inicia la sesión del escritorio. El siguiente procedimiento funciona en un escritorio KDE:
/.kde/env/ssh-agent.sh
mkdir ~/.kde/env vim ~/.kde/env/ssh-agent.sh chmod u+x ~/.kde/env/ssh-agent.shcon estos contenidos:
someone@localhost:~/.kde/env$ cat -n ssh-agent.sh 1 #!/bin/sh 2 /usr/bin/ssh-agent -s > $HOME/.ssh/agent-env.sh 3 $HOME/.ssh/agent-env.sh > /dev/null
La opción -s
de ssh-agent
le indica que debe generar
comandos de Bourne shell en stdout.
Esta es la conducta por defecto a menos que SHELL
sea de la familia de shells csh
.
La alternativa es usar la opción -c
la cual genera comandos
C-shell. Esta es la conducta por defecto si SHELL
es csh
o tcsh
.
La redirección de la línea 2 produce el guión que es ejecutado en la línea 3:
someone@localhost:~/src$ cat $HOME/.ssh/agent-env.sh SSH_AUTH_SOCK=/tmp/ssh-LDdzn31114/agent.31114; export SSH_AUTH_SOCK; SSH_AGENT_PID=31115; export SSH_AGENT_PID; echo Agent pid 31115;
~/.kde/shutdown
:
mkdir ~/.kde/shutdown vim ~/.kde/shutdown/shutdown-ssh.sh chmod u+x ~/.kde/shutdown/shutdown-ssh.sh
con los siguientes contenidos:
someone@localhost:~/.kde/shutdown$ cat -n shutdown-ssh.sh 1 #!/bin/sh 2 /usr/bin/ssh-agent -k
La opción recomendada es aprovechar el agente ssh creado al arrancar las X.
Puede que quiera que las identidades se añadan tan pronto como entra en su
escritorio KDE. En ese caso cambie los contenidos de /.kde/env/ssh-agent.sh
por algo parecido a esto:
someone@localhost:~/.kde/env$ cat -n ssh-agent.sh 1 #!/bin/sh 2 /usr/bin/ssh-add $HOME/.ssh/id_dsa 3 /usr/bin/ssh-add $HOME/.ssh/thatmachinebackupidentity
La metodología usada en los párrafos anteriores no es válida si
no somos el usuario que arranca las X. Este es el caso si estamos
ya en una sesión ssh
o hemos cambiado de usuario
ejecutando su
(switch user)
o bien queremos ejecutar un proceso por lotes bajo un cron.
En estos casos keychain puede ayudar.
Comencemos usando la opción -k
para suprimir los
agentes activos y asegurarnos que empezamos desde una
situación inicial:
lusasoft@LusaSoft:~/.ssh$ keychain -k all KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/ Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL * All lusasoft's ssh-agent(s) (5678) are now stopped * All lusasoft's gpg-agent(s) (6823) are now stopped
La opción -k
tiene la sintáxis:
-k whichLas siguientes opciones son válidas para
which
:
all
eliminar a todos los agentes y terminar
others
eliminar a los agentes que no sean de keychain
mine
eliminar a los agentes keychain
dejando el resto.
Cuando se ejecuta keychain
comprueba si existe ya un agente ssh-agent
ejecutándose.
Si no es el caso arranca uno. Si existe no cargará uno nuevo. Sin embargo
es necesario que el usuario o el script llamen a ~/.keychain/europa-sh
para tener acceso al agente.
lusasoft@LusaSoft:~/.ssh$ keychain ~/.ssh/id_dsa KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/ Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL * Initializing /home/lusasoft/.keychain/LusaSoft-sh file... * Initializing /home/lusasoft/.keychain/LusaSoft-csh file... * Initializing /home/lusasoft/.keychain/LusaSoft-fish file... * Starting ssh-agent * Initializing /home/lusasoft/.keychain/LusaSoft-sh-gpg file... * Initializing /home/lusasoft/.keychain/LusaSoft-csh-gpg file... * Initializing /home/lusasoft/.keychain/LusaSoft-fish-gpg file... * Starting gpg-agent * Adding 1 ssh key(s)... Identity added: /home/lusasoft/.ssh/id_dsa (/home/lusasoft/.ssh/id_dsa)Salva las variables de entorno en
~/.keychain/${HOSTNAME}-sh
,
lusasoft@LusaSoft:~$ tree .keychain/ .keychain/ |-- LusaSoft-csh |-- LusaSoft-csh-gpg |-- LusaSoft-fish |-- LusaSoft-fish-gpg |-- LusaSoft-sh `-- LusaSoft-sh-gpgEstos ficheros contienen los comandos para establecer las variables de entorno. Por ejemplo:
$ cat -n .keychain/europa-sh 1 SSH_AUTH_SOCK=/tmp/ssh-ctTDo22823/agent.22823; export SSH_AUTH_SOCK; 2 SSH_AGENT_PID=22824; export SSH_AGENT_PID;De este modo las subsiguientes llamadas no interactivas a ssh - por ejemplo, cron jobs - pueden hacer un
source
del correspondiente
guión y conectarse con el único agente obviando asi la necesidad de solicitar las claves.
$ source ~/.keychain/europa-sh $ ssh orion Linux orion 2.6.8-2-686 #1 Tue Aug 16 13:22:48 UTC 2005 i686 GNU/LinuxSi abrimos otra terminal deberemos hacer de nuevo la llamada a
source ~/.keychain/europa-sh
.
Por supuesto, lo mejor es poner la llamada a keychain
y a source ~/.keychain/europa-sh
en nuestro fichero de arranque ~/.bashrc
o bash_profile
.
/usr/bin/keychain ~/.ssh/id_dsa source ~/.keychain/europa-sh
Cuando se ejecuta, keychain verifica que la clave especificada es conocida por el agente. Si no es así nos solicitará la passphrase.
Véase la siguiente secuencia de comandos. Primero ponemos una passphrase a la identidad por defecto:
lusasoft@LusaSoft:~$ ssh-keygen -p Enter file in which the key is (/home/lusasoft/.ssh/id_rsa): /home/lusasoft/.ssh/id_dsa Key has comment '/home/lusasoft/.ssh/id_dsa' Enter new passphrase (empty for no passphrase): *************** Enter same passphrase again: *************** Your identification has been saved with the new passphrase.A continuación limpiamos los agentes:
lusasoft@LusaSoft:~$ keychain --clear KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/ Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL * Found existing ssh-agent (6927) * Found existing gpg-agent (6951) * ssh-agent: All identities removed. * gpg-agent: All identities removed.
Cargamos de nuevo keychain con la identidad por defecto:
lusasoft@LusaSoft:~$ keychain ~/.ssh/id_dsa KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/ Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL * Found existing ssh-agent (6927) * Found existing gpg-agent (6951) * Adding 1 ssh key(s)... Identity added: /home/lusasoft/.ssh/id_dsa (/home/lusasoft/.ssh/id_dsa)Ahora se nos solicita la passphrase (por defecto mediante ssh-askpass). Después de escribirla la identidad es añadida al agente.
lusasoft@LusaSoft:~$ keychain --nogui ~/.ssh/id_dsa KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/ Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL * Found existing ssh-agent (6927) * Found existing gpg-agent (6951) * Adding 1 ssh key(s)... Enter passphrase for /home/lusasoft/.ssh/id_dsa: ********************* Identity added: /home/lusasoft/.ssh/id_dsa (/home/lusasoft/.ssh/id_dsa)
keychain
soporta también gpg-agent. Por defecto arranca
todos los agentes disponibles. Se puede limitar los agentes arrancados
usando la opción --agents
. Por ejemplo --agents 'gpg,ssh'
La llamada a keychain
creará un nuevo
agente si el fichero /home/pp2/.keychain/europa-sh
queda obsoleto
(por ejemplo, si SSH_AUTH_SOCK
referencia un socket que no existe
o no existe un proceso con pid el referenciado en SSH_AGENT_PID
).
Véase la siguiente sesión de comandos:
pp2@europa:~$ ps -fA | grep agent casiano 6976 6911 0 10:57 ? 00:00:00 /usr/bin/ssh-agent x-session-manager pp2 22824 1 0 12:42 ? 00:00:00 ssh-agent pp2 22848 1 0 12:42 ? 00:00:00 gpg-agent --daemon pp2 32569 30843 0 13:06 pts/13 00:00:00 grep agent pp2@europa:~$ kill -9 22824 pp2@europa:~$ ps -fA | grep agent pp2 3165 30843 0 13:07 pts/13 00:00:00 grep agent casiano 6976 6911 0 10:57 ? 00:00:00 /usr/bin/ssh-agent x-session-manager pp2 22848 1 0 12:42 ? 00:00:00 gpg-agent --daemon pp2@europa:~$ keychain KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/ Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL * Initializing /home/pp2/.keychain/europa-sh file... * Initializing /home/pp2/.keychain/europa-csh file... * Initializing /home/pp2/.keychain/europa-fish file... * Starting ssh-agent * Found existing gpg-agent (22848) pp2@europa:~$ ps -fA | grep agent pp2 3198 1 0 13:07 ? 00:00:00 ssh-agent pp2 3225 30843 0 13:08 pts/13 00:00:00 grep agent casiano 6976 6911 0 10:57 ? 00:00:00 /usr/bin/ssh-agent x-session-manager pp2 22848 1 0 12:42 ? 00:00:00 gpg-agent --daemon
La opción -eval
de keychain
hace que
keychain
envíe a stdout el contenido del script.
Así podemos arrancar el agente y añadirle la clave en un paso con:
pp2@europa:~/Lbook$ eval `keychain -eval ~/.ssh/id_dsa`