Renuncia de responsabilidad:
La versión original de este artículo fue publicada por IBM
developerWorks y es propiedad de Westtech Information Services. Este
documento es una versión actualizada del artículo original y contiene
mejoras introducidas por el Equipo de Documentación de Gentoo.
Este documento carece de soporte activo.
|
Gestión de claves para OpenSSH, Parte 3
1.
Agente intermedio y mejoras de keychain
Muchos de nosotros usamos las excelencias de OpenSSH como sustituto
cifrado y seguro de los venerables comandos telnet y rsh. Una de las
características que más intrigan de OpenSSH es la habilidad para
validar usuarios usando los protocolos RSA y DSA, que se basan en un
par de claves numéricas complementarias. Uno de los principales
atractivos de la validación RSA y DSA es la promesa de ser capaz de
establecer conexiones a sistemas remotos sin suministrar una
contraseña. Para más antecedentes, vea las entregas anteriores de esta
serie sobre gestión de claves para OpenSSH, que cubren validación
RSA/DSA (Parte 1) y ssh-agent y keychain
(Parte 2), respectivamente.
Desde la Parte 2 publicada en developerWorks en Septiembre de 2001, y
más tarde referenciados en Slashdot y Freshmeat (véase Recursos más adelante en este artículo los
enlaces a estos sitios), muchas personas han empezado a usar keychain,
y le han realizado algunos cambios, he recibido sobre unos 20 parches
de gran calidad de desarrolladores de todo el mundo. He incorporado
muchos de estos parches al código de keychain, que está ahora en la
versión 1.8 (vea Recursos). Envío mis más
sincero agradecimiento a todos aquellos que enviaron parches, informes
de errores, y notas de agradecimiento.
Ajustando la seguridad de ssh
En mi último
artículo, he pasado algún tiempo comentando los beneficios de
seguridad y las ventajas del funcionamiento de ssh-agent. Pocos días
después de que el segundo artículo apareciera en developerWorks,
recibí un e-mail de Charles Karney de Sharnof Corporation, que
amablemente me informó de las nuevas habilidades del nuevo agente
intermedio de validación de OpenSSH, le echaremos un vistazo en
breve. Además, Charles hizo hincapié que la ejecución de ssh-agent en
máquinas poco fiables es muy peligroso: si alguien logra acceso como
superusuario en el sistema, entonces sus claves descifradas puedes ser
extraídas desde ssh-agent. Aunque la extracción de las claves sería
algo difícil, está dentro de las habilidades de los crackers
profesionales. Y ante mero hecho de que el robo de la clave privada
sea medianamente posible deberemos tomar medidas en primer lugar para
evitar que suceda.
Para formular una estrategia para proteger nuestras claves privadas,
debemos primero poner las máquinas a las que accedemos dentro de una
de dos categorías. Si un anfitrión particular está bien asegurado o
aislado -- siendo poco probable el acceso con éxito del superusuario
por medio de una vulnerabilidad -- entonces la máquina debe ser
considerada un anfitrión de confianza. Sin embargo, si una máquina es
usada por muchas personas o si tiene alguna duda acerca de la
seguridad del sistema, entonces la máquina debería ser considerada
como un anfitrión no confiable. De esta manera, incluso si la
seguridad del sistema se ve comprometida, en primer lugar no habrá un
ssh-agent a mano del intruso para extraer las claves.
Sin embargo, esto crea un problema, si no se puede ejecutar ssh-agent
en anfitriones no confiables, entonces ¿como podemos establecer conexiones
ssh, sin contraseñas y seguras en estos sistemas? La respuesta es usar
solamente ssh-agent y keychain en anfitriones confiables, y usar la nueva
capacidad de OpenSSH de validación intermedia para extender la
validación sin contraseña en los anfitriones inseguros. En pocas palabras,
el trabajo de la validación intermedia es permitir a las sesiones ssh
remotas contactar con un ssh-agent que esté ejecutándose en un sistema
confiable.
Agente de validación intermedia
Para tener una idea de cómo funciona la validación intermedia, primero
deje que veamos una hipotética situación donde el usuario drobbins
tiene un ordenador portátil llamado lappy, un servidor de confianza
llamado trustbox, y otros dos sistemas inseguros a los que debe tener
acceso, llamados notrust1 y notrust2, respectivamente. Actualmente,
utiliza ssh-agent junto con keychain en las cuatro máquinas, de la
siguiente manera:
Ilustración 1.1: ssh-agent ejecutandose en máquinas confiables y no confiables |
 |
El problema con este enfoque es que si alguien consigue acceso de
superusuario en notrust1 o notrust2, entonces, por supuesto, es
posible que estas personas extraigan las claves desde el ahora
vulnerable proceso ssh-agent. Para solucionar este problema, drobbins
para la ejecución de ssh-agent y keychain en los inseguros anfitriones
notrust1 y notrust2. De hecho, es incluso más cuidadoso, drobbins
decide usar solamente ssh-agent y keychain en lappy. Esto limita la
exposición de sus claves privadas descifradas, protegiéndolas contra
el robo.
Ilustración 1.2: ssh-agent ejecutándose solamente en lappy; una configuración muy segura |
 |
Por supuesto, el problema con este enfoque es que drobbins solamente
puede establecer conexiones sin contraseña desde lappy. Veamos como
habilitar la validación intermedia y solucionar este problema.
Suponiendo que todas las máquinas están ejecutando la versión más
reciente de OpenSSH, podemos solucionar este problema mediante el uso
de la validación intermedia. la validación intermedia permite a los
procesos ssh remotos contactar con el ssh-agent que esté en ejecución
en su máquina local segura -- en lugar de requerir que una versión de
ssh-agent sea ejecutada en la misma máquina desde la que salga por
ssh. Esto por lo general le permite ejecutar ssh-agent (y keychain) en
una sola máquina, y significa que todas las conexiones ssh que
procedan (ya sea directa o indirectamente) desde esta máquina van a
utilizar su ssh-agent local.
Para habilitar la validación intermedia, añadimos la siguiente línea
en /etc/ssh/ssh_config de lappy y trustbox. Tenga en
cuenta que este es el archivo de configuración de ssh
(ssh_config), no del servicio sshd
(sshd_config):
Listado de Código 1.1: Añada esta línea a su /etc/ssh/ssh_config |
ForwardAgent Yes
|
Ahora, para sacar ventaja de la validación intermedia, drobbins se
puede conectar desde lappy a trustbox, y a continuación desde trustbox
hacia notrust1 sin suministrar contraseña desde ninguna
conexión. Ambos procesos ssh "llaman" a ssh-agent ejecutado en lappy:
Listado de Código 1.2: Aprovechando 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!
$
|
Si intenta una configuración similar y se da cuenta que la transmisión
no funciona, pruebe utilizando ssh -A en lugar del anterior ssh
a secas para habilitar explícitamente la validación intermedia. Aquí
hay un diagrama sobre lo que sucede detrás del escenario cuando
accedemos a trustbox y notrust1 usando la validación intermedia:
Ilustración 1.3: Agente intemedio en acción |
 |
Como puede ver, cuando ssh conecta a trustbox, mantiene una conexión
con el ssh-agent ejecutado en lappy. Cuando una conexión ssh se
realiza desde trustbox hacia notrust1, este nuevo proceso ssh mantiene
la conexión validada por el anterior ssh, extendiendo la cadena de
manera efectiva. Si esta cadena de validación puede ser extendida más
allá de notrust1 a otros anfitriones depende de como
/etc/ssh/ssh_config en notrust1 esté configurado. Mientas
el agente intermedio este habilitado, todas las partes de la cadena
serán capaces de validarse usando el ssh-agent ejecutado en el seguro
lappy,
Ventajas del agente de conexión intermedia
La validación intermedia ofrece una serie de ventajas de seguridad no
mostradas. Para convencerme de la importancia del agente de conexión
intermedia, Charles Karney ha compartido conmigo estas tres conceptos
de seguridad:
-
La clave privada se guarda sólo en la máquina de confianza. Esto
evita que usuarios malintencionados recolecten su clave encriptada
desde el disco y traten de romper la encriptación.
-
ssh-agent sólo se ejecuta en la máquina de confianza. Esto evita
que un intruso realice un volcado de memoria de un proceso
ssh-agent remoto y entonces extraiga su clave descifrada desde el
volcado.
-
Dado que sólo tendrá que teclear su contraseña desde su máquina de
confianza, evita cualquier furtivo logeador de pulsaciones del
teclado que pueda capturar su contraseña cuando es introducida.
El inconveniente de confiar en el agente de validación intermedio es
que no resuelve el problema que permita a los cron jobs aprovechar la
validación RSA/DSA. Una solución a este problema es crear todos los
cron jobs que necesiten la validación RSA/DSA para que sean ejecutados
en una máquina de confianza de su LAN. Si es necesario, estos cron
jobs pueden utilizar ssh para conectarse a sistemas remotos para
automatizar copias de seguridad, sincronizar ficheros, y así
sucesivamente.
Ahora que hemos visto la conexión del agente de validación intermedia,
es el turno de las mejoras recientemente introducidas en el propio
guión keychain.
Mejoras en el funcionamiento de keychain
Gracias a los parches enviados por los usuarios, muchas mejoras
importantes se han introducido en el código fuente de keychain. Varios
de los parches enviados por usuarios fueron en relación a la
funcionalidad. Por ejemplo, recordará que keychain ha creado un
fichero ~/.ssh-agent; el nombre de este fichero ha
cambiado a ~/.ssh-agent-[hostname] de modo que keychain
puede trabajar con los directorios home montados por NFS para que se
puedan acceder desde varios anfitriones físicos. Además del fichero
~/.ssh-agent-[hostname], ahora hay un fichero
~/.ssh-agent-csh-[hostname] que puede ser leído por
consolas csh y compatibles. Por último, una nueva opción
--nocolor ha sido añadida a fin de que la característica
coloración pueda ser desactivada en caso de que se utilice un terminal
no compatible vt100.
Correcciones de compatibilidades de la consola
Si bien la funcionalidad de las mejoras han sido importantes, la gran
mayoría de las correcciones se han ocupado de los problemas de
compatibilidad de la consola. Verá, mientras keychain 1.0 requiere de
bash, versiones posteriores fueron cambiadas para trabajar con
cualquier consola compatible con sh. Este cambio permite a keychain
trabajar "de forma poco común" en casi cualquier sistema UNIX,
incluyendo Linux, BSD, Solaris, IRIX, y AIX así como de otras
plataformas UNIX. Si bien la transición a sh y a la compatibilidad
general UNIX ha sido un camino lleno de baches, también ha sido una
tremenda experiencia de aprendizaje. La creación de un único guión
que funcione en todas estas plataformas ha sido muy difícil,
principalmanete por mi, ¡sencillamente no tengo acceso a la mayoría de
estos sistemas operativos!. Afortunadamente, lo hicieron los usuarios
de keychain de todo mundo, y muchos han proporcionado gran ayuda en la
identificación de problemas de compatibilidad y presentando parches
para solucionarlos.
Realmente hay dos tipos de problemas de compatibilidad que tenían que
ser solucionados. Primeramente, necesitaba asegurar que keychain,
integraba expresiones y operadores que estuvieran plenamente
soportados bajos todas las implementaciones de sh, incluyendo todas
las consolas sh populares libres y las comerciales UNIX, zsh (en modo
compatible sh), y las versiones 1 y 2 de bash. Estos son algunas de
las correcciones de compatibilidad de consola enviadas por los
usuarios que fueron aplicadas al código fuente de keychain:
Dado que las antiguas consolas sh no soportan el convenio ~ para
referirse al directorio home del usuario, las líneas que usaban ~
fueron cambiadas para usar $HOME en su lugar:
Listado de Código 1.3: cambiando a $HOME |
hostname=`uname -n`
pidf=${HOME}/.ssh-agent-${hostname}
cshpidf=${HOME}/.ssh-agent-csh-${hostname}
|
A continuación, todas las referencias al código fuente fueron
cambiadas por un . para asegurar la compatibilidad con la purista
/bin/sh de NetBSD, que no es compatible con el comando source:
Listado de Código 1.4: Alegrando NetBSD |
if [ -f $pidf ]
then
. $pidf
else
SSH_AGENT_PID="NULL"
fi
|
A lo largo del camino, también he ido aplicando algunos parches
relacionados con el rendimiento. Un experimentado programador de
guiones de consola me informó que en lugar de "crear" un fichero
tecleando touch foo, tu puedes hacer esto en su lugar:
Listado de Código 1.5: Creando ficheros |
> foo
|
Sobre la base de usar la sintaxis interna de la consola en lugar de un
binario externo, un fork() es evitado y el guión se convierte en algo
más eficiente. > foo debería trabajar con cualquier consola compatible
sh; sin embargo, no parece estar soportado por ash. Esto no debería
ser un problema para la mayoría de la gente, ya que ash es una consola
para un disco de recuperación en lugar de algo que la gente use en el
día a día básico.
Preguntando a la plataforma por los ejecutables
Obtener un guión que trabaje en múltiples sistemas operativos UNIX
requiere algo más que ceñirse a la sintaxis pura de sh. Recuerde que,
la mayoría de los guiones también hacen llamadas a comandos externos,
tales como grep, awk, ps, y otros, y estos comandos deben ser llamados
de una manera compatible en la medida de lo posible. Por ejemplo,
mientras el comando echo incluido en la mayoría de los UNIX reconoce
la opción -e, Solaris no -- simplemente imprime -e hacia
stdout cuando se utiliza. Por lo tanto ,con el fin de tratar con
Solaris, keychain ahora autodetecta si echo -e funciona:
Listado de Código 1.6: Analizando la salida de Solaris |
if [ -z "`echo -e`" ]
then
E="-e"
fi
|
Arriba, E se establece en -e si -e es soportada, entonces, echo
se puede llamar de la siguiente manera:
Listado de Código 1.7: Mejorar echo |
echo $E Usage: ${CYAN}${0}${OFF} [ ${GREEN}options${OFF} ] ${CYAN}sshkey${OFF} ...
|
Mediante el uso de echo $E en lugar de echo -e, la
opción -e puede ser dinámicamente activada o desactivada según sea
necesario.
pidof, ps
Probablemente, la más significativa revisión de compatibilidad ha
implicado cambios en como keychain detecta los actuales procesos
ssh-agent en ejecución. Anteriormente yo estaba usando el comando
pidof para hacerlo, pero he tenido que eliminarlo desde que varios
sistemas no tienen un pidof. Realmente, pidof no es la mejor solución
de todos modos, ya que lista todos los procesos ssh-agent ejecutándose
en el sistema, independientemente del usuario, cuando realmente
estamos interesados en todos los procesos ssh-agent propiedad del
actual UID.
Así que, en lugar de depender de pidof, pasamos sobre las tuberías de
la salida ps a grep y awk con el fin de extraer el proceso ids
necesario. Esto es un arreglo enviado por un usuario:
Listado de Código 1.8: Tuberías mejor que pidof |
mypids=`ps uxw | grep ssh-agent | grep -v grep | awk '{print $2}'`
|
La tubería establecerá la variable mypids a los valores de todos los
procesos ssh-agent propiedad del actual usuario. El comando grep -v
grep es parte de la tubería para garantizar que el procesos grep
ssh-agent no se convierta en parte de nuestra lista de PID.
Si bien este enfoque es un buen concepto, usando ps se abrió toda una
nueva lata de gusanos ya que las opciones de ps no están
estandarizadas a través de las diferentes BSD y System V derivados de
UNIX. He aquí un ejemplo: mientras ps uxw trabaja bajo Linux, no
funciona bajo IRIX. Y mientras ps -u username -f trabaja bajo
Linux, IRIX y Solaris, no funciona bajo BSD, que sólo entiende el
estilo BSD de opciones ps. Para evitar este problema, keychain
autodetecta si el ps del sistema actual trabaja con la sintaxis BSD o
System V antes de ejecutar la tubería ps:
Listado de Código 1.9: Detectando BSD vs. 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
|
Para asegurar que el comando ps trabaja con ambos System V y estilo
BSD, el guión hace un "simulacro" de ps uxw, mostrando alguna salida,
si el código de error de este comando es igual a cero, sabemos que ps
uxw trabaja y ajustamos el valor psopts adecuadamente. Sin embargo, si
ps uxw devuelve un código de error distinto de cero (lo que indica que
tenemos que usar las opciones del estilo BSD), haremos una prueba de
ps -u `whoami` -f, nuevamente mostrando toda la salida. En este
punto, esperamos haber encontrado una variante BSD o System V de ps
que podamos usar. Si no, mostramos un error y salimos. Pero es muy
probable que uno de los dos comandos ps trabaje, en cuyo caso se
ejecutará la línea final del anterior fragmento de código, nuestra
tubería ps. Mediante el uso de la variable $psopts expandida
inmediatamente después de ps, estamos en condiciones de pasar las
opciones correctas al comando ps.
La tubería ps también contiene una verdadera joya grep, que me fue
amablemente enviada por Hans Peter Verne. Observe que grep -v
grep ya no es parte de la tubería; en su lugar, se ha eliminado y
grep "ssh-agent" ha sido cambiado por grep
"[s]sh-agent". Este único comando grep termina haciendo lo
mismo que grep ssh-agent | grep -v grep; ¿se puede figurar por
qué?.
Listado de Código 1.10: Ligero truco con grep |
mypids=`ps $psopts 2>/dev/null | grep "[s]sh-agent" | awk '{print $2}'` > /dev/null 2>&1
|
¿Perplejo? Si ha decidido que un grep "ssh-agent" y grep
"[s]sh-agent" deberían coincidir con las mismas líneas de texto,
está en lo cierto. ¿Entonces porqué hacer que generen resultados
diferentes cuando la salida de ps es entubada hacia ellos? He aquí
como funciona: cuando se utiliza grep "[s]sh-agent", cambia la forma
en que el comando grep aparece en el listado de procesos ps. De esta
manera, prevenimos que grep coincida consigo mismo, ya que la cadena
[s]sh-agent no coincide con la expresión regular [s]sh-agent. ¿No es
brillante? Si todavía no lo pilla, juegue con grep un poco más y lo
logrará pronto.
Conclusión
Con este artículo concluye mi cobertura de OpenSSH. Afortunadamente,
ha aprendido lo suficiente para empezar a utilizar OpenSSH para
asegurar sus sistemas. El próximo mes continuaré con la serie de
artículos con la "Guía avanzada de implementación de ficheros"
2.
Recursos
|