El protocolo SSH/SecSH nació para intentar que las comunicaciones en internet fuesen más seguras, esto lo consigue eliminando el envio de las contraseñas sin cifrar y mediante la encriptación de toda la información que se transmite.
En principio podríamos pensar en SSH como un sustituto del telnet, el rexec y el rsh, pero la realidad es que SSH permite mucho más que la simple identificación de usuarios y ejecución de programas en máquinas remotas. A través de una conexión SSH se puede encapsular cualquier protocolo y gracias a la habilidad para crear túneles, tanto remotos como locales, podemos llegar a traspasar routers y cortafuegos.
Este documento se centra en OpenSSH, existen otras implementaciones del protocolo SSH, pero no todas son libres (licencia BSD) ni tan potentes como lo es OpenSSH, a parte del mero hecho de que hoy por hoy, OpenSSH es la implementación del protocolo SSH más extendida, pudiendo funcionar en un gran número de sistemas operativos y viniendo preinstalado en casi todas las distribuciones de GNU/Linux.
#####################################################################
SSH (Secure Shell) es un conjunto de estándares y protocolo de red que permite establecer una comunicación a través de un canal seguro entre un cliente local y un servidor remoto. Utiliza una clave pública cifrada para autenticar el servidor remoto y, opcionalmente, permitir al servidor remoto autenticar al usuario. SSH provee confidencialidad e integridad en la transferencia de los datos utilizando criptografía y MAC (Message Authentication Codes, o Códigos de Autenticación de Mensaje). De modo predeterminado, escucha peticiones a través del puerto 22 por TCP.
SFTP (SSH File Transfer Protocol) es un protocolo que provee funcionalidad de transferencia y manipulación de ficheros a través de un flujo confiable de datos. Comúnmente se utiliza con SSH para proveer a éste de transferencia segura de ficheros.
SCP (Secure Copy, o Copia Segura) es una protcolo seguro para transferir ficheros entre un anfitrión local y otro remoto, a través de SSH. Básicamente, es idéntico a RCP (Remote Copy, o Copia Remota), con la diferencia de que los datos son cifrados durante la transferencia para evitar la extracción potencial de información a través de programas de captura de las tramas de red (packet sniffers). SCP solo implementa la transferencia de ficheros, pues la autenticación requerida es realizada a través de SSH.
OpenSSH (Open Secure Shell) es una alternativa de código abierto, con licencia BSD, hacia la implementación propietaria y de código cerrado SSH creada por Tatu Ylönen. OpenSSH es un proyecto creado por el equipo de desarrollo de OpenBSD y actualmente dirigido por Theo de Raadt. Se considera es más segura que su contraparte propietaria debido a la constante auditoría que se realiza sobre el código fuente por parte de una gran comunidad de desarrolladores, una ventaja que brinda al tratarse de un proyecto de fuente abierta.
OpenSSH incluye servicio y clientes para los protocolos SSH, SFTP y SCP.
URL: http://www.openssh.org/.
•
•
•
openssh-3.5p1-6
openssh-clients-3.5p1-6
openssh-server-3.5p1-6
Antes de continuar verifique siempre la existencia de posibles actualizaciones de seguridad:
yum -y install openssh openssh-server openssh-clients
Edite /etc/ssh/sshd_config. A continuación se analizarán los parámetros a modificar.
Una forma de elevar considerablemente la seguridad al servicio de SSH, es cambiar el número de puerto utilizado por el servicio, por otro que solo conozca el administrador del sistema. A este tipo de técnicas se les conoce como Seguridad por Oscuridad. La mayoría de los delincuentes informáticos utiliza guiones que buscan servidores que respondan a peticiones a través del puerto 22. Cambiar de puerto el servicio de SSH disminuye considerablemente la posibilidad de una intrusión a través de este servicio.
/etc/ssh/sshd_config
Fichero central de configuración del servicio SSH.
Port 22
SSH trabaja a través del puerto 22 por TCP. Puede elegirse cualquier otro puerto entre el 1025 y 65535. ejemplo:
Port 52341
Por defecto, el servicio de SSH responderá peticiones a través de todas las interfaces del sistema. En algunos casos es posible que no se desee esto y se prefiera limitar el acceso sólo a través de una interfaz a la que sólo se pueda acceder desde la red local. Para tal fin puede establecerse lo siguiente, considerando que el servidor a configurar posee la IP 192.168.1.254:
ListenAddress 192.168.1.254
Establece si se va a permitir el acceso directo del usuario root al servidor SSH. Si se va a permitir el acceso hacia el servidor desde redes públicas, resultará prudente utilizar este parámetro con el valor no.
PermitRootLogin no
Establece si se permite o no la ejecución remota de aplicaciones gráficas. Si se va a acceder hacia el servidor desde red local, este parámetro puede quedarse con el valor yes. Si se va a permitir el acceso hacia el servidor desde redes públicas, resultará prudente utilizar este parámetro con el valor no.
X11Forwarding yes
Permite restringir el acceso por usuario y, opcionalmente, anfitrión desde el cual pueden hacerlo. El siguiente ejemplo restringe el acceso hacia el servidor SSH para que solo puedan hacerlo los usuarios fulano y mengano, desde cualquier anfitrión.
AllowUsers fulano mengano
Permite restringir el acceso por usuario y, opcionalmente, anfitrión desde el cual pueden hacerlo. El siguiente ejemplo restringe el acceso hacia el servidor SSH para que solo puedan hacerlo los usuarios fulano y mengano, solamente desde los anfitriones 10.1.1.1 y 10.2.2.1.
El servicio de SSH puede iniciar, detenerse o reiniciar a través de un guión similar a los del resto del sistema. De tal modo, podrá iniciar, detenerse o reiniciar a través del mandato service y añadirse al arranque del sistema en un nivel o niveles de corrida en particular con el mandato chkconfig.
Para ejecutar por primera vez el servicio, utilice:
AllowUsers fulano@10.1.1.1 mengano@10.1.1.1 fulano@10.2.2.1 mengano@10.2.2.1
service sshd start
Para hacer que los cambios hechos a la configuración surtan efecto, utilice:
service sshd restart
Para detener el servicio, utilice:
service sshd stop
De forma predeterminada, el servicio SSH está incluido en todos los niveles de corrida con servicio de red. Para desactivar el servicio Sshd de los niveles de corrida 2, 3, 4 y 5, ejecute:
chkconfig --level 2345 sshd off
Para acceder a través de intérprete de mandatos hacia el servidor, basta con ejecutar desde el sistema cliente el mandato ssh definiendo el usuario a utilizar y el servidor al cual conectar:
ssh usuario@servidor
Para acceder hacia un puerto en particular, se utiliza el parámetro -p. En el siguiente ejemplo, utilizando la cuanta del usuario juan, se intentará acceder hacia el servidor con dirección IP 192.168.0.99, el cual tiene un servicio de SSH que responde peticiones a través del puerto 52341.
ssh -p 52341 juan@192.168.0.99
Para acceder a través de SFTP hacia el servidor, basta con ejecutar desde el sistema cliente el mandato sftp definiendo el usuario a utilizar y el servidor al cual conectar:
sftp usuario@servidor
El intérprete de mandatos de SFTP es muy similar al utilizado para el protocolo FTP y tiene las mismas funcionalidades.
Para acceder hacia un puerto en particular, en el cual está trabajando el servicio de SSH, se hace través de el parámetro -o, con la opción Port=número de puerto. En el siguiente ejemplo, utilizando la cuenta del usuario juan, se accederá a través de SFTP hacia el servidor 192.168.0.99, el cual tiene trabajando el servicio de SSH en el puerto 52341.
sftp -o Port=52341 juan@192.168.0.99
Si dispone de un escritorio en GNU/Linux, con GNOME 2.x, puede acceder hacia servidores SSH a través del protocolo SFTP utilizando el administrador de ficheros (Nautilus) para realizar transferencias y manipulación de ficheros, especificando el URI (Uniform Resource Locator o Localizador Uniforme de Recursos) «sftp:», seguido del servidor y la ruta hacia la que se quiere acceder, seguido del puerto, en el caso que sea distinto al 22.
Nautilus, accediendo hacia un directorio remoto a través de SFTP.
Para realizar transferencias de ficheros a través de SCP, es necesario conocer las rutas de los directorios objetivo del anfitrión remoto. A continuación se describen algunas de las opciones más importantes del mandato scp.
-p
-P
-r
Preserva el tiempo de modificación, tiempos de acceso y los modos del fichero original.
Especifica el puerto para realizar la conexión.
Copia recursivamente los directorios especificados.
En el siguiente ejemplo, se transferirá el fichero algo.txt, preservando tiempos y modos, hacia el directorio de inicio del usuario fulano en el servidor 192.169.0.99.
scp -p algo.txt fulano@192.168.0.99:~/
En el siguiente ejemplo, se transferirá la carpeta Mail, junto con todo su contenido, preservando tiempos y modos, hacia el directorio de inicio del usuario fulano en el servidor 192.169.0.99.
scp -rp Mail fulano@192.168.0.99:~/
En el siguiente ejemplo, se transferirá la carpeta Mail, junto con todo su contenido, desde el directorio de inicio del usuario fulano en el servidor 192.169.0.99, cuyo servicio de SSH escucha peticiones a través del puerto 52341, preservando tiempos y modos, hacia el directorio del usuario con el que se está trabajando en el anfitrión local.
scp -P 52341 -rp fulano@192.168.0.99:~/Mail ./
Si se utiliza un cortafuegos con políticas estrictas, como por ejemplo Shorewall, es necesario abrir el puerto 22 por UDP (SSH).
Las reglas para el fichero /etc/shorewall/rules de Shorewall correspondería a algo similar a lo siguiente:
#ACTION SOURCE DEST PROTO DEST SOURCE # PORT PORT(S)1 ACCEPT net fw tcp 22 #LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE
Si la red de área local (LAN) va a acceder hacia el servidor recién configurado, es neceario abrir el puerto correspondiente.
#ACTION SOURCE DEST PROTO DEST SOURCE # PORT PORT(S)1 ACCEPT net fw tcp 22 ACCEPT loc fw tcp 22 #LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE
#####################################################################
#scp -P 45459 -Cpr /path/server/local USUARIO@IP_SERVER_REMOTO:/path/server/remoto
#ssh -p 45459 USUARIO@IPSERVER_REMOTO
Debido a la cantidad de sistemas operativos sobre los que OpenSSH puede funcionar y sobre todo al monstruoso número de distribuciones de GNU/Linux que existen, en este documento, se asumirá que el usuario ya tiene instalado OpenSSH en su equipo o que al menos conoce el sistema operativo que usa y por lo tanto, sabe como instalar programas nuevos, teniendo la capacidad de instalar OpenSSH.
Sobre la sintaxis de los distintos comandos que se muestran cabe destacar que tendrán el siguiente formato:
ssh [opciones] [usuario@]máquina
Donde ssh es simplemente el nombre del programa a ejecutar, todo lo que aparece a continuación del nombre del programa son los parámetros, los que se encuentran entre corchetes se consideran opcionales, pueden ponerse o se pueden omitir, por ejemplo, usuario@ es un parámetro que indica el nombre del usuario a emplear seguido de una arroba, si se omite, se asumirá un valor por defecto (el usuario que se está empleando para ejecutar ssh). Por el contrario, los parámetros que no están entre corchetes son obligatorios, como sucede con el parámetro máquina.
La sintaxis todavía puede ser más elaborada, tal es el caso del siguiente ejemplo:
scp [opciones] [[usuario@]máquina:]archivo ... [[usuario@]máquina:]archivo
Aquí podemos apreciar que hay corchetes dentro de parámetros que ya están entre corchetes, cuanto más internos sean los corchetes, más opcionales serán los parámetros, por ejemplo, podemos especificar el nombre de un archivo como "dir/arch.txt", lo cual asumirá que es un archivo en la máquina frente a la que estamos sentados, pero también podemos poner "equipo.remoto:dir/arch.txt", en este otro caso estamos indicando que el archivo se encuentra en el equipo con el nombre equipo.remoto, finalmente, podemos poner "manolo@equipo.remoto:dir/arch.txt", con esto especificamos que queremos acceder con el usuario manolo a la máquina con el nombre equipo.remoto y al archivo dir/arch.txt.
De está sintaxis sólo queda destacar que los puntos suspensivos quieren decir que el parámetro que les precede se puede repetir tantas veces como sea necesario, en este caso concreto, significa que podemos especificar varios archivos.
Recuerdo que cuando era pequeño, tenía una profesora de matématicas que habitualmente, despues de explicar la lección, se dirigia hacia la pizarra y diciendo que una foto vale más que mil palabras se ponía a resolver varios problemas en la pizarra, despues de eso, por desgracia, nos mandaba los deberes.
Haciendo caso a las sabias palabras de mi profesora, aparecerán gran cantidad de capturas mostrando ejemplos de como usar las herramientas que vienen con OpenSSH. Para intentar disminuir la confusión que puede generar el trabajar con equipos remotos, delante de cada comando que se escriba habrá un prompt (apuntador de la línea de comandos que indica que podemos escribir), el formato de este prompt siempre será el mismo:
[usuario@máquina] $ df -h
El prompt es todo lo que va desde el principio de la línea hasta el signo dolar ($), la parte entre corchetes muestra el usuario que se está empleando y separado mediante una arroba, el nombre del equipo informático donde se está poniendo el comando, no tiene por que ser el equipo frente al que estamos sentados, sino que también puede ser un equipo remoto al que estamos accediendo. Todo lo que aparece a la derecha del signo dolar es el propio comando a escribir.
La forma más simple de utilizar el SSH es para abrir una shell interactiva en una máquina remota, la invocación del programa no tiene ningún misterio, simplemente ponemos el comando ssh seguido de la IP o el nombre de la máquina a la que queremos conectar:
ssh [usuario@]máquina
El parámetro opcional usuario sirve para indicar la cuenta de usuario a la que se quiere conectar en el equipo remoto, de no especificarse ningún usuario se empleará el que se está usando para invocar al cliente de ssh. El parámetro máquina es la IP o el nombre del equipo informático al que queremos conectar.
A modo de ejemplo, una posible forma de realizar una conexión SSH a una máquina remota llamada remoto.ejemplo.com sería la siguiente:
[hell@local] $ ssh remoto.ejemplo.com
Continuando con el ejemplo anterior, si todo fuese bien, el cliente de SSH debería de pedirnos la contraseña del usuario hell, ya que según el prompt del ejemplo, ese es el usuario que estamos usando en el momento de invocar al cliente de SSH. En caso de poner mal la clave, el cliente nos la pediría otra vez, pero no esperes que te la pida más de tres veces, ademas este es el caso de que la cuenta de usuario hell no exista en la máquina remoto.ejemplo.com:
[hell@local] $ ssh remoto.ejemplo.com
hell@remoto.ejemplo.com's password:
Permission denied, please try again.
hell@remoto.ejemplo.com's password:
Permission denied, please try again.
hell@remoto.ejemplo.com's password:
Permission denied (password).
[hell@local] $
Imaginemos que nuestra cuenta en remoto.ejemplo.com no se llama hell, sino que se llama manolo, en este caso tendríamos que invocar al cliente de ssh con un parámetro de la forma usuario@máquina, como en el siguiente ejemplo:
[hell@local] $ ssh manolo@remoto.ejemplo.com
manolo@remoto.ejemplo.com's password:
Last login: Sat Dec 17 16:30:18 2005 from local.ejemplo.com
[manolo@remoto] $
Hemos abierto una pty (pseudo-terminal) en la que se está ejecutando una shell, podemos escribir comandos y la shell los interpretará como si estuviéramos delante del equipo remoto.ejemplo.com, vale, esto es lo mismo que telnet, la única diferencia que la conexión está encriptada. Para que el cliente de SSH termine tenemos que cerrar la shell, poniendo exit, pulsado Ctrl-d o como se os ocurra.
[manolo@remoto] $ exit
Connection to remoto.ejemplo.com closed.
[hell@local] $
En lugar de abrir una shell interactiva, también podemos hacer que el cliente de SSH ejecute un comando y nos envie su salida, basta con poner el comando con todos sus parámetros a continuación del nombre del equipo remoto, por ejemplo para ver el contenido de la carpeta personal del usuario manolo en el equipo remoto.ejemplo.com podríamos poner lo siguiente:
[hell@local] $ ssh manolo@remoto.ejemplo.com ls
manolo@remoto.ejemplo.com's password:
a.tar.gz
doc
test.txt
misc
src
[hell@local] $
Para, por ejemplo, ver el contenido del archivo test.txt podríamos poner:
[hell@local] $ ssh manolo@remoto.ejemplo.com cat test.txt
manolo@remoto.ejemplo.com's password:
Este es un archivo de texto que
no contiene nada en especial,
tan sólo sirve para ocupar algo
de espacio en el disco duro.
[hell@local] $
Que pena, no parece que contenga ninguna información privilegiada que nos pudiese interesar, en fin, a lo nuestro. Esto en principio puede parecer estupido, ¿para qué quiero ejecutar comandos si puedo usar perfectamente una shell interactiva?, bueno, pues ahí es donde entra la imaginación de cada uno. A modo de ejemplo, fijemonos arriba en el archivo a.tar.gz, ¿qué pasaría si quisieramos extraer dicho archivo en el equipo que estamos usando?, ¿cómo podríamos hacerlo?. Tradicionalmente nos lo bajaríamos, extraeríamos su contenido y opcionalmente borraríamos el archivo comprimido. OpenSSH tiene herramientas para poder transmitir archivos por SSH, pero a pesar de ello, vamos a explotar el echo de que al ejecutar un comando de forma remota el cliente de SSH nos envia su salida, con esto y la creación de una tubería (pipe), podemos extraer el archivo directamente sin tener que bajarnoslo para luego borrarlo:
[hell@local] $ ssh manolo@remoto.ejemplo.com cat a.tar.gz | tar xvzf -
manolo@remoto.ejemplo.com's password:
a
a/a.txt
a/b.txt
a/c.txt
[hell@local] $
Analicemos el comando anterior, en primer lugar ejecutamos el comando "cat a.tar.gz" en el equipo remoto.ejemplo.com usando para ello la cuenta de usuario manolo. El programa ssh redirecciona la salida estandar del comando cat hacia la salida estandar de nuestra consola. Hasta aquí ningún problema, pues es el caso del ejemplo de antes cuando quisimos ver el contenido del archivo test.txt, pero a continuación nos encontramos con una barra vertical (|) seguida del comando "tar xvzf -". La barra vertical le dice al shell que cree una tubería entre dos comandos, esto es, redireccionar la salida estandar del comando que hay a su izquierda hacia la entrada del comando que hay a su derecha, con lo cual, en este caso, lo que conseguimos es descomprimir directamente el archivo remoto a.tar.gz en nuestra máquina local, sin tener que salvar dicho archivo previamente en nuestro disco duro.
Hemos comprobado la ventaja de que ssh redireccione la salida estandar de los comandos que ejecuta remotamente hacia la salida estandar de nuestra consola, pero la cosa no se queda ahí, ¿qué sucede con la entrada del comando ssh?, pues bien, ssh, también redirecciona su entrada hacia la entrada del comando que ejecute remotamente, ¿esto qué significa?, significa que podemos coger unos datos locales, procesarlos remotamente y obtener el resultado localmente.
Veamoslo con otro ejemplo, imaginemos que queremos invocar el comando wc en un equipo remoto para contar el número de líneas, palabras y bytes que tiene el archivo test.txt que tenemos almacenado en nuestro disco duro:
[hell@local] $ cat test.txt | ssh manolo@remoto.ejemplo.com wc
manolo@remoto.ejemplo.com's password:
5 24 124
[hell@local] $
Hagamos otro análisis de este comando. En primer lugar está el "cat test.txt", que lo único que hace es leer el contenido del archivo test.txt y mostrarlo por la salida estandar. A continuación tenemos una barrita vertical (|) que le dice al shell que cree una tubería para redireccionar la salida del comando cat hacia la entrada del comando ssh. El comando ssh ejecuta en la máquina remoto.ejemplo.com el programa wc, al que en su entrada le pasa la salida del comando "cat test.txt", a su vez, ssh nos envia la salida de wc para que podamos verla.
Nada impide que creemos otra tubería para procesar la salida del comando wc con otra herramienta, ni tampoco que nos compliquemos la vida elaborando comandos más complejos, pues ahí entra la imaginación de cada uno.
Una de las herramientas de las que dispone OpenSSH para transmitir archivos entre dos equipos remotos es scp, su nombre proviene de "Secure CoPy". Su manejo es bastante sencillo, básicamente hay que especificarle una lista de archivos origen y al final el archivo o ruta destino, de la siguiente manera:
scp [[usuario@]máquina:]ruta ... [[usuario@]máquina:]ruta
Como se puede apreciar, el formato en el que se indican los archivos a copiar es: usuario@máquina:ruta, el primer parámetro (usuario) indica el nombre de la cuenta de usuario que se quiere usar en el sistema remoto, en el caso de no espeficicarlo, se asumirá el usuario que se está empleando en el sistema local. El parámetro máquina es el nombre o la IP del equipo remoto, en caso de que sea el equipo que estamos usando omitimos este campo. Finalmete el parámetro ruta no es más que la ruta hacia el archivo que queremos copiar.
A modo de ejemplo, imaginemos que queremos bajarnos el archivo a.tar.gz que esta en el directorio del usuario manolo en el equipo remoto.ejemplo.com, podríamos invocar al scp de la siguiente manera:
[hell@local] $ scp manolo@remoto.ejemplo.com:a.tar.gz .
manolo@remoto.ejemplo.com's password:
a.tar.gz 100% 5008KB 1.6MB/s 00:03
[hell@local] $
Ahora imaginemos que queremos subir ese mismo archivo que nos hemos bajado a la carpeta personal del usuario hell en el equipo remoto.ejemplo.com, serviría algo como:
[hell@local] $ scp a.tar.gz remoto.ejemplo.com:
hell@remoto.ejemplo.com's password:
a.tar.gz 100% 5008KB 1.6MB/s 00:03
[hell@local] $
Con scp tambíen podemos copiar archivos de varias máquinas remotas, por ejemplo, si quisiéramos bajarnos el archivo a.tar.gz del equipo remoto.ejemplo.com y el archivo b.tar.gz del equipo remoto2.ejemplo.com, asumiendo que la cuenta de usuario a usar en ambos equipos es la que estamos empleando en el equipo local, nos bastaría con:
[hell@local] $ scp remoto.ejemplo.com:a.tar.gz remoto2.ejemplo.com:b.tar.gz .
hell@remoto.ejemplo.com's password:
a.tar.gz 100% 5008KB 1.6MB/s 00:03
hell@remoto2.ejemplo.com's password:
b.tar.gz 100% 5203KB 1.6MB/s 00:04
[hell@local] $
OpenSSH dispone de varios métodos para verificar la identidad de un usuario remoto, uno de ellos es el uso de contraseñas de usuarios, pero otro de los métodos se basa en la autenticación RSA, en donde se dispone de un juego de llaves privada/pública que garantiza la identidad de un usuario intentando conectarse al equipo remoto. El juego de llaves tiene la propiedad de que lo que se encripta con una, sólo se puede desencriptar con la otra, pero sin embargo, a partir de la llave pública no se puede derivar la llave privada.
Para asegurarse de que un usuario es quien dice ser por medio de criptografía pública OpenSSH emplea el siguiente procedimiento: Primero, el servidor genera un número aleatorio que encripta con la llave pública del usuario y le envia el resultado al cliente, si el usuario es quien dice ser entonces no tendrá ningún problema en desencriptarlo. El cliente aplicará una transformación predefinida a dicho número y lo enviará de vuelta al servidor, el cual, revisará dicho resultado y de ser correcto, dará acceso al cliente.
Un sistema parecido al anterior es el que se emplea también para verificar que el servidor al que se está conectando es el correcto y no estamos siendo victimas de un ataque de tipo Monkey In the Middle.
Para poder trabajar con llaves públicas, lo primero que tendremos que hacer será configurar el servidor de SSH para que las acepte. Habitualmente los archivos de configuración de OpenSSH se ubican en la carpeta /etc/ssh, en este caso, el archivo que nos interesa es /etc/ssh/sshd_config, lo abrimos con un editor de textos y corregimos los valores de las siguientes opciones relacionadas con las llaves públicas:
#RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
La primera opción (RSAAuthentication) sirve para indicar cuando se permitirá autenticación RSA, está opción esta habilitada por defecto, y en el ejemplo está comentada porque sólo sirve para la versión 1 del protocolo SSH.
La segunda opción (PubkeyAuthentication) es la que especifica si se podrán usar llaves públicas para demostrar la autenticidad de un usuario. Si su valor es yes como en el ejemplo, entonces se podrán emplear las llaves públicas, si por el contrario su valor es no, entonces el uso de llaves públicas quedará prohibido.
La tercera opción (AuthorizedKeysFile) especifica el archivo que contiene las llaves públicas empleadas para la autenticación de los usuarios. Por defecto suele ser el archivo .ssh/autorized_keys, dentro de la carpeta personal de cada usuario.
Finalmente, en caso de haber alterado el archivo de configuración del servidor, para que los cambios sean efectivos, será necesario reiniciar el servidor de SSH.
Para poder crear nuevas llaves privadas y sus correspondientes llaves públicas, OpenSSH dispone de una herramienta llamada ssh-keygen, esta herramienta puede crear llaves RSA para el protocolo SSH versión 1, cuyo uso se desaconseja y aquí no se va a hablar de ellas, por otro lado, también puede generar llaves RSA o DSA para el protocolo SSH versión 2. Para especificar que tipo de llave crear, se emplea el parámetro -t seguido del tipo de llave: "rsa" o "dsa". Por ejemplo, para crear una llave RSA podemos poner:
[hell@local] $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/hell/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/hell/.ssh/id_rsa. Your public key has been saved in /home/hell/.ssh/id_rsa.pub. The key fingerprint is: c0:40:50:27:e8:d9:b8:55:d6:a4:5f:af:e5:30:5d:9b hell@local [hell@local] $
Por el contrario, para generar una llave DSA, simplemente:
[hell@local] $ ssh-keygen -t dsa Generating public/private dsa key pair. Enter file in which to save the key (/home/hell/.ssh/id_dsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/hell/.ssh/id_dsa. Your public key has been saved in /home/hell/.ssh/id_dsa.pub. The key fingerprint is: f5:b2:f3:2d:43:1b:22:44:98:6c:fe:42:df:a3:15:09 hell@local [hell@local] $
Los anteriores comandos piden los mismos datos, el primero, en donde salvar la llave privada, si simplemente pulsamos intro, se salvará en la ruta por defecto (la indicada entre paréntesis), a no ser que emplees varias llaves privadas, la ruta por defecto es una buena opción, ya que el cliente la usará sin necesidad de que el usuario tenga que especificarla.
Las siguientes dos cosas que pide son la frase clave con la que encriptar la llave privada y una petición de que se repita la frase para cerciorarse de que no se han cometido errores al escribirla la primera vez. Para la frase con la que encriptar la llave privada se puede emplear cualquier carácter (letras, numeros, signos de puntuación, espacios), en principio el tamaño de la frase puede ser arbitrario, pero ssh-keygen se quejará si es menor de cuatro carácteres. En caso de no introducir ninguna frase, la llave privada quedará sin encriptar, lo cual podria ser útil para realizar algunas automatizaciones como podría ser el realizar copias de seguridad, pero, para uso habitual, se desaconseja dejar las llaves privadas sin encriptar por el peligro que puede representar que estas sean robadas.
A continuación el ssh-keygen muestra donde se ha salvado la llave privada (/home/hell/.ssh/id_dsa) y donde está la llave pública que le corresponde (/home/hell/.ssh/id_dsa.pub), que no es más que el mismo nombre de archivo con la extensión .pub añadida al final.
En la última línea imprime una huella dactilar que sirve para identificar la llave que acabamos de crear, seguida de un comentario que puede servir para identificar la llave pública.
Despues de haber creado un juego de llaves privada y pública, nos encontramos con el dilema de que hacer con ellas, lo primero es mantener la llave privada secreta, por defecto ssh-keygen establecerá los permisos del archivo con esta llave para que sólo el dueño pueda leerla y modificarla. Por el contrario la llave pública podrá ser leida por cualquier usuario, pues por algo es pública.
Pero para poder autenticarnos en un equipo remoto con nuestra llave privada, lo único que tendremos que hacer es añadir nuestra llave pública en el archivo .ssh/authorized_keys dentro del directorio personal del usuario al que queremos acceder (generalmente $HOME/.ssh/authorized_keys).
El primer dilema que se nos plantea es el cómo enviamos nuestra llave pública al equipo remoto, una forma, en caso de que podamos acceder a el usando SSH con contraseñas de usuario para autenticarnos, sería mediante SCP, a modo de ejemplo, imaginemos que despues de crear el juego de llaves tenemos lo siguiente en nuestro directorio .ssh:
[hell@local] $ ls -1
~/.ssh id_rsa id_rsa.pub
[hell@local] $
No es más que un juego de llaves RSA, ahora la máquina remota donde queremos instalar nuestra llave se llama remoto.ejemplo.com, y la cuenta de usuario es la misma que la que estamos empleando en el sistema que estamos utilizando, entonces podríamos poner:
[hell@local] $ scp ~/.ssh/id_rsa.pub remoto.ejemplo.com:
mi_llave.pub hell@remoto.ejemplo.com's
password: id_rsa.pub 100% 398 0.4KB/s 00:00
[hell@local] $
De esta manera en la máquina remota tendremos el archivo mi_llave.pub que contiene nuestra llave pública, ahora tan sólo nos resta crear el directorio .ssh, en caso de que no exista, y añadir la llave pública al archivo $HOME/.ssh/authorized_keys, para ello, podemos conectarnos mediante SSH y usar el comando cat. Una sesión SSH a modo de ejemplo sería la siguiente:
[hell@local] $ ssh ejemplo.remoto.com hell@remoto.ejemplo.com's password:
[hell@remoto] $ mkdir .ssh [hell@remoto] $ chmod 700 .ssh
[hell@remoto] $ cd .ssh [hell@remoto] $ cat ../my_llave.pub >> authorized_keys
[hell@remoto] $
Ahora, la próxima vez que nos conectemos al servidor remoto.ejemplo.com, en lugar de pedirnos la contraseña del usuario, nos pedira la frase clave con la que la encriptamos nuestra llave privada:
[hell@local] $ ssh ejemplo.remoto.com Enter passphrase for key '/home/hell/.ssh/id_rsa':
[hell@remoto] $
A veces se puede dar el caso de que dispongamos de varias llaves para autenticarnos, los motivos pueden ser diversos, como por ejemplo que nuestra llave habitual no nos permita redireccionar puertos en la máquina remota, o, por el contrario, que una llave pública ejecuta automáticamente un proceso para hacer copias de seguridad, también existe la posibilidad de que nuestra llave habitual este restringida y necesitemos usar otra que no lo este.
Sea cual sea la causa por la que tenemos que emplear otra llave, la manera de hacerlo es mediante el parámetro -i seguido del archivo que contiene la llave privada a emplear. A modo de ejemplo, supongamos que la máquina a la que queremos conectar se llama remoto.ejemplo.com y que la llave que vamos a emplear está en el archivo llave_acceso1.key, un comando como el siguiente sería suficiente:
[hell@local] $ ssh -i llave_acceso1.key ejemplo.remoto.com Enter passphrase for key 'llave_acceso1.key':
[hell@remoto] $
Por defecto, ssh-keygen genera llaves de 2048 bits, cuanto más grande sea una llave, más segura será. En la actualidad, ssh-keygen admite que las llaves tengan un mínimo de 512 bits y aunque en la página del manual no se indique, el máximo son 32768 bits, pero este último valor podría cambiar a medida que la potencia de los equipos informáticos se incremente. No obstante, con la liberación de la versión 4.3 de OpenSSH, sus desarrolladores decidieron fijar el tamaño de las llaves DSA a 1024 bits, pudiendo alterarse tan sólo el tamaño para las llaves RSA.
Por lo general el número de bits para la llave que escoge ssh-keygen por defecto es suficiente, pero para quienes prefieran otros valores, se puede especificar el tamaño de la llave con el parámetro -b seguido del número de bits que se desea que tenga la llave. Un ejemplo para generar una llave RSA de 4096 bits podría ser el siguiete:
[hell@local] $ ssh-keygen -t rsa -b 4096 Generating public/private rsa key pair. Enter file in which to save the key (/home/hell/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/hell/.ssh/id_rsa. Your public key has been saved in /home/hell/.ssh/id_rsa.pub. The key fingerprint is: 4b:29:23:e9:20:c1:e5:32:6e:fa:b4:91:9a:01:b5:10 hell@local [hell@local] $
En el momento de su creación, ssh-keygen nos permite añadir un comentario a las claves públicas, por defecto el comentario que pone es del tipo usuario@máquina, pero podemos emplear el parámetro -C seguido del comentario que queramos, para así diferenciar más facilmente nuestra llave pública del resto de llaves. A modo de ejemplo, supongamos que queremos crear una clave de pruebas de tipo RSA con el comentario "Clave de pruebas":
[hell@local] $ ssh-keygen -t rsa -C "Clave de pruebas" Generating public/private rsa key pair. Enter file in which to save the key (/home/hell/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/hell/.ssh/id_rsa. Your public key has been saved in /home/hell/.ssh/id_rsa.pub. The key fingerprint is: 97:47:90:2d:b6:d9:ab:6d:91:41:ed:ad:dc:fb:a0:64 Clave de pruebas [hell@local] $
En alguna ocasión nos veremos en la necesidad de querer cambiar la frase con la que una llave privada fue encriptada, o en el caso de que la llave privada no estubiese encriptada, querer encriptarla. Para conseguir este objetivo podemos invocar al programa ssh-keygen con el parámetro -p, veamos un ejemplo:
[hell@local] $ ssh-keygen -p Enter file in which the key is (/home/hell/.ssh/id_rsa): Enter old passphrase: Key has comment '/home/hell/.ssh/id_rsa' Enter new passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved with the new passphrase. [hell@local] $
En primer lugar nos pide la frase con la que está encriptada (old passphrase), a continuación, nos pide que introduzcamos la nueva frase (new passphrase), entre paréntesis, nos indica que si no ponemos nada, la llave privada quedará sin encriptar (empty for no passphrase). Después nos pide que repitamos la frase, para asegurarse de que no hemos cometido errores al escribirla la primera vez y finalmente, graba la llave privada encriptada con la nueva frase.
Una de las ventajas de emplear llaves públicas frente al uso de contraseñas de usuario es que no tenemos que recordar nada más que una única frase, la frase con la que hemos cifrado nuestra llave privada. Eso es un avance, pero OpenSSH dispone de una herramienta que nos puede evitar el trámite de tener que andar escribiendo dicha frase cada vez que establezcamos una nueva conexión. Esta herramienta se llama ssh-agent y tiene la capacidad de recordar las llaves privadas que tenemos.
Al ejecutar el agente ssh (ssh-agent), este crea un socket UNIX y establece la variable de entorno SSH_AUTH_SOCK con el nombre del socket. Por razones de seguridad los permisos del socket son ajustados para que tan sólo el usuario actual pueda acceder al socket. Además, el agente también crea la variable de entorno SSH_AGENT_PID y establece su valor con su PID (identificador de programa).
Cuando el cliente de SSH necesita autenticar a un usuario, lo primero que hace es mirar si existe la variable de entorno SSH_AUTH_SOCK, de ser así, la usa para establecer una conexión con el agente, el agente no le pasa la llave privada al cliente de SSH, sino que es el propio agente el que se encarga de realizar la autenticación, de forma que la llave privada nunca sea expuesta a los clientes.
Actualmente hay varias formas de cargar el agente, una de ellas es poniendo simplemente ssh-agent en la línea de comandos:
[hell@local] $ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-nfxOw32113/agent.32113; export SSH_AUTH_SOCK;
SSH_AGENT_PID=32114; export SSH_AGENT_PID;
echo Agent pid 32114;
[hell@local] $
La salida anterior se corresponde a una shell Bourne y no es más que los comandos que habría que ejecutar para establecer las variables de entorno SSH_AUTH_SOCK y SSH_AGENT_PID, en el caso de emplear una shell derivada del csh la salida sería ligeramente distinta. El programa ssh-agent intenta averiguar el tipo de shell que se está usando, no obstante, se le puede pasar la opción -c para indicar una shell derivada de csh, o la opción -s para que muestre los comandos apropiados para una shell derivada del Bourne. Por ejemplo, para especificarle que estamos usando una shell csh:
[hell@local] $ ssh-agent -c
setenv SSH_AUTH_SOCK /tmp/ssh-hLBzi32149/agent.32149;
setenv SSH_AGENT_PID 32150;
echo Agent pid 32150;
[hell@local] $
El inconveniente de invocar el comando ssh-agent de la anterior manera está en que tenemos que establecer las variables de entorno manualmente, copiando y pegando, o escribiéndolas a mano, pero para hacerlo más cómodo, podemos emplear el comando eval de la siguiente forma:
[hell@local] $ eval `ssh-agent`
Agent pid 32171
[hell@local] $
De esa manera, logramos que la salida de ssh-agent se evalúe, quedando las variables de entorno establecidas. Podemos verificarlo así:
[hell@local] $ set | grep SSH
SSH_AGENT_PID=32174
SSH_AUTH_SOCK=/tmp/ssh-QUpBw32173/agent.32173
[hell@local] $
La otra manera de iniciar el agente es especificándole un programa a ejecutar, de forma que el agente establecerá las variables de entorno y ejecutará el programa, por ejemplo, para iniciar una shell csh con el agente:
[hell@local] $ ssh-agent bash
local:hell {1} env | grep SSH
SSH_AUTH_SOCK=/tmp/ssh-DBKNN10192/agent.10192
SSH_AGENT_PID=1921
local:hell {2} exit
[hell@local] $
También, por ejemplo, se puede ejecutar con el agente una terminal xterm:
[hell@local] $ ssh-agent xterm
El agente nada más iniciarse no contiene ninguna llave, para agregarlas se emplea la herramienta ssh-add, si se ejecuta sin argumentos intenta añadir los archivos ~/.ssh/id_rsa, ~/.ssh/id_dsa y ~/.ssh/identity:
[hell@local] $ ssh-add
Enter passphrase for /home/hell/.ssh/id_rsa:
Identity added: /home/hell/.ssh/id_rsa (/home/hell/.ssh/id_rsa)
Identity added: /home/hell/.ssh/id_dsa (/home/hell/.ssh/id_dsa)
[hell@local] $
En el caso anterior ssh-add primero encuentra el archivo ~/.ssh/id_rsa y pide la frase con la que está cifrada la llave que contiene, entonces añade dicha llave al agente, después, localiza el archivo ~/.ssh/id_dsa que contiene otra llave, pero al estar cifrada con la misma frase que la primera llave, no vuelve a pedir la frase, si no que la descifra y la añade directamente al agente.
Si lo que queremos es añadir otra llave distinta a las tres que busca por defecto, lo único que tenemos que hacer es pasar el archivo con la llave como parámetro de ssh-add. Por ejemplo, para añadir una llave llamada millave.key:
[hell@local] $ ssh-add millave.key
Enter passphrase for millave.key:
Identity added: millave.key (millave.key)
[hell@local] $
En caso de querer ver que llaves contiene el agente, podemos pasarle la opción -l a la herramienta ssh-add, y obtendremos una salida como la siguiente:
[hell@local] $ ssh-add -l
2048 1f:2b:61:83:c7:f8:27:73:4d:03:0a:92:40:da:b8:bb /home/hell/.ssh/id_rsa (RSA)
1024 78:f2:ac:c0:0b:80:57:e7:fb:98:05:cd:1e:36:69:84 /home/hell/.ssh/id_dsa (DSA)
2048 d1:a7:cb:de:1b:bf:ef:04:04:2f:33:fc:31:f3:80:b3 millave.key (DSA)
[hell@local] $
Cada línea representa una llave. La primera columna muestra el tamaño en bits de la llave, la segunda se corresponde con la huella dactilar de la llave, la tercera columna es el archivo que contiene la llave y la última columna, indica entre paréntesis el tipo de llave que es, RSA o DSA.
También se puede emplear la opción -L que mostrará las llaves públicas, lo cual puede ser útil para añadirlas al archivo authorized_keys de una máquina remota.
[hell@local] $ ssh-add -L
ssh-rsa AAAAB3NzaC1...XnFBZjRf8cqDbugZRVeHYGvRqrNdv/9w== /home/hell/.ssh/id_rsa
ssh-dss AAAAB3NzaC1...6GRYhh2JxuPcr9kwlD7ZUjFrgElDFrng== /home/hell/.ssh/id_dsa
ssh-dss AAAAB3NzaC1...ZumWVFBO5E+fhyaZegOb8Rsz08J8LxOQ== millave.key
[hell@local] $
Nota: Cada llave aparece en una línea, pero como cada línea es muy larga, he eliminado parte del contenido de la llave pública, sustituyéndolo por puntos suspensivos para que así quepa bien en la pantalla.
También podemos eliminar llaves del agente empleando la herramienta ssh-add con la opción -d seguida de la llave pública que le corresponde a la llave privada que queremos que el agente borre de su memoria. Por ejemplo, para que olvide nuestra llave RSA:
[hell@local] $ ssh-add -d .ssh/id_rsa
Identity removed: .ssh/id_rsa (.ssh/id_rsa.pub)
[hell@local] $
No obstante, también podemos eliminar todas las llaves que tenga el agente empleando la opción -D, ejemplo:
[hell@local] $ ssh-add -D
All identities removed.
[hell@local] $
Cuando no necesitamos usar el agente, pero no queremos que se olvide de nuestras llaves, como en el caso de dejar el equipo en el que estamos trabajando para ir a tomar un cafetín, podemos optar por bloquear el agente, para ello tan sólo hace falta pasarle la opción -x a la herramienta ssh-add, la cual nos pedirá una contraseña con la que luego podremos desbloquear el agente:
[hell@local] $ ssh-add -x
Enter lock password:
Again:
Agent locked.
[hell@local] $
Luego, cuando necesitemos volver a usar el agente, podemos desbloquearlo ejecutando la herramienta ssh-add con la opción -X, ssh-add entonces nos pedirá la contraseña para desbloquear el agente:
[hell@local] $ ssh-add -X
Enter lock password:
Agent unlocked.
[hell@local] $
Probablemente más de una vez tengamos que acceder a un equipo remoto que se encuentra dentro de una red privada (LAN), pero tendremos que hacerlo a través de un router, primero conectando al router, y después conectando al equipo remoto. Estableciendo así dos conexiones, una entre el equipo local y el router, y la otra entre el router y el equipo remoto dentro de la LAN.
El agente ssh será capaz de autenticarnos en la primera conexión sin ningún problema, pero para que nos autentique en la segunda, este deberá ser reenviado a través de la primera conexión. Por defecto, OpenSSH no está configurado para reenviar el agente, con lo que habrá que ejecutar el cliente con la opción -A, por ejemplo, para conectar con el router y reenviarle el agente:
[hell@local] $ ssh -A router.ejemplo.com
[hell@router] $
Ahora, si miramos las variables de entorno, podemos apreciar como en la sesión que hemos abierto en el router, efectivamente el agente se ha reenviado:
[hell@router] $ echo $SSH_AUTH_SOCK
/tmp/ssh-sQwzt23661/agent.23661
[hell@router] $
¿Cómo funciona esto realmente? Bien, al iniciar la sesión interactiva en el router, el cliente de SSH crea un socket UNIX y establece la variable SSH_AUTH_SOCK apuntando hacia el socket. Cuando se ejecuta otro cliente de SSH para conectar desde el router a otro equipo, el nuevo cliente de SSH se conecta a ese socket, y el primer cliente de SSH reenvia todo lo que recibe por ese socket hacia el agente que se esta ejecutando en nuestro equipo local.
Gracias a este mecanismo, podemos hacer que nuestro agente nos siga autenticando en el resto de equipos a los que nos conectemos, de alguna manera, es como si el agente pudiese viajar con nosotros. Por ejemplo, si desde la sesión interactiva del router queremos conectarnos a un equipo dentro de la LAN llamado remoto.ejemplo.com, podremos poner algo como lo siguiente:
[hell@router] $ ssh -A remoto.ejemplo.com
[hell@remoto] $ echo $SSH_AUTH_SOCK
/tmp/ssh-OsvWx13346/agent.13346
[hell@remoto] $
Se puede apreciar, que se ha creado un nuevo socket UNIX y se ha establecido la variable SSH_AUTH_SOCK apuntando hacia el, lo cual permitirá que nuestro agente, que esta ejecutandose en nuestro equipo local, pueda seguir autenticandonos en las conexiones que realicemos desde remoto.ejemplo.com.
Se puede hacer que el agente recuerde las llaves durante un tiempo determinado, a partir del cual, el agente las olvidará. Por defecto, el agente no olvida las llaves núnca (mientras se siga ejecutando, o no se le fuerce a olvidarlas), pero se le puede especificar la opción -t seguida del tiempo de vida que se quiere que tengan las llaves:
[hell@local] $ ssh-agent -t 60 bash
[hell@local] $
El comando anterior inicia un nuevo shell bash con el agente, y establece el límite de vida de las llaves por defecto en 60 segundos. Pero también se puede establecer un tiempo límite de vida para cada llave al añadirla con el comando ssh-add, la forma de hacerlo, es la misma, especificando la opción -t seguida del tiempo límite de vida que se quiere que tenga la llave, por ejemplo:
[hell@local] $ ssh-add -t 120 remote
Enter passphrase for remote:
Identity added: remote (remote)
Lifetime set to 120 seconds
[hell@local] $
De esta forma, pasados dos minutos, el agente eliminará la llave remote de su memoria y no podremos seguir empleandola para autenticarnos a no ser que se la añadamos de nuevo al agente.
OpenSSH nos permite crear dos clases de túneles: locales y remotos. En los locales se redirecciona un puerto de la máquina local (cliente) hacia un puerto en una máquina remota a la que el servidor tenga acceso. En los túneles remotos, lo que se hace es redireccionar un puerto desde una máquina remota a la que el servidor tenga acceso hacia un puerto de la máquina local.
La forma de crear túneles locales con OpenSSH es mediante la opción -L, cuya sintaxis es:
-L [dirección_escucha:]puerto_escucha:máquina_remota:puerto_máquina_remota
En caso de emplear direcciones IPv6, se puede utilizar la siguiente sintaxis:
-L [dirección_escucha/]puerto_escucha/máquina_remota/puerto_máquina_remota
Los túneles locales se establecen de la siguiente forma: primero se crea un conector (socket) de escucha en la máquina local, asociado al puerto puerto_escucha y, opcionalmente, a la dirección dirección_escucha. Cuando se realice una conexión al puerto en el que está escuchando el conector, OpenSSH encauzará la conexión a través del canal seguro hacia la máquina remota a la que el servidor tenga acceso, indicada por la IP máquina_remota y el puerto puerto_máquina_remota.
Para demostrar como funcionan los túneles locales, me basaré en el siguiente diagrama ilustrativo:
En el diagrama tenemos que nos encontramos en el equipo llamado alpha.local.net, y lo que queremos es acceder al servidor web (puerto 80) que hay en el equipo web.remoto.net, el problema es que entre nosotros y el servidor hay un router denominado router.remoto.net que nos impide acceder al servidor. Obviamente, el router ha de tener un servidor de SSH funcionando al que nosotros tengamos acceso, cumpliendose esta premisa, lo que vamos a hacer es redireccionar el puerto 80 (web) del servidor web.remoto.net hacia, por ejemplo, el puerto 8080 de nuestro equipo:
[hell@alpha.local.net] $ ssh-agent -L 8080:web.remoto.net:80 router.remoto.net
Enter passphrase for key '/home/hell/.ssh/id_dsa':
[hell@router.remoto.net] $
Hemos iniciado una sesión SSH interactiva en el router, pero además, ahora, en nuestro equipo, se habrá abierto el puerto 8080:
[hell@alpha.local.net] $ netstat -an | grep LISTEN
tcp 0 0 127.0.0.1.8080 *.* LISTEN
tcp 0 0 *.22 *.* LISTEN
[hell@alpha.local.net] $
El túnel está creado, ahora, mientras no cerremos la sesión SSH con el router, cada vez que nos conectemos al puerto 8080 de nuestro equipo (localhost o alpha.local.net), nuestra conexión estará siendo reenviada al puert 80 del servidor web.remoto.net. Por ejemplo, para acceder a el desde un navegador, tendríamos que usar una URL del estilo: http://localhost:8080/
Hasta aquí, bien, pero... si nos fijamos, en la salida del comando netstat que hay arriba, el túnel sólo acepta conexiones desde alpha.local.net, porque el conector (socket) que creo está asociado a la IP 127.0.0.1, también conocida como localhost, que sirve para referirse al propio equipo, así es que, ¿qué pasaría si lo que buscásemos fuese que otro equipo se conecte al servidor web.remoto.net a través de nuestro equipo? Añadamos ese nuevo equipo a nuestro diagrama:
Para permitir que beta.local.net también pueda beneficiarse de nuestro túnel, tenemos que hacer que el socket no se asocie con la IP 127.0.0.1, esto se consigue poniendo un asterisco (*), o, la IP del propio alpha.local.net en el parámetro opcional dirección_escucha, ejemplo:
[hell@alpha.local.net] $ ssh-agent -L *:8080:web.remoto.net:80 router.remoto.net
Enter passphrase for key '/home/hell/.ssh/id_dsa':
[hell@router.remoto.net] $
Si ahora ejecutásemos otra vez el comando netstat en alpha.local.net veríamos lo siguiente:
[hell@alpha.local.net] $ netstat -an | grep LISTEN
tcp 0 0 *.8080 *.* LISTEN
tcp 0 0 *.22 *.* LISTEN
[hell@alpha.local.net] $
El conector del túnel ahora acepta conexiones de cualquier equipo, perfectamente, ahora podríamos abrir un navegador en beta.local.net y poner la siguiente URL: http://alpha.local.net:8080/, la conexión sería canalizada a través del canal seguro establecido entre alpha.local.net y router.remoto.net, hasta llegar al puerto 80 de web.remoto.net.
La forma de crear túneles remotos con OpenSSH es mediante la opción -R, que tiene la siguiente sintaxis:
-R [dirección_escucha:]puerto_escucha:máquina_remota:puerto_máquina_remota
Pero si se quieren emplear direcciones IPv6, también se permite usar la siguiente sintaxis:
-R [dirección_escucha/]puerto_escucha/máquina_remota/puerto_máquina_remota
El mecanismo empleado para establecer los túneles remotos es: se crea un conector (socket) en el servidor asociado al puerto indicado por puerto_escucha y, opcionalmente, a la dirección IP dirección_escucha. Posteriormente, cuando se realice una conexión a dicho conector, la conexión será encauzada a través del canal seguro hacia una máquina a la que el equipo local tenga acceso, indicada por la IP máquina_remota y el puerto puerto_máquina_remota.
A modo de ejemplo sobre como se establecen los túneles remotos, basemonos en los equipos del siguiente diagrama:
Para ponernos en situación, imaginemos que nos encontramos en el equipo alpha.local.net y que lo que queremos es que alguien desde el equipo terminal.remoto.com se pueda conectar a un servidor web (puerto 80) que tenemos en nuestro equipo, el problema está en que el router deja que nosotros podamos conectarnos a terminal.remoto.com, pero impide que el pueda conectarse a nosotros. Entonces, creamos un túnel remoto de la siguiente forma:
[hell@alpha.local.net] $ ssh-agent -R 8080:localhost:80 terminal.remoto.net
Enter passphrase for key '/home/hell/.ssh/id_dsa':
[hell@terminal.remoto.net] $
Ahora, se habrá creado un conector (socket) en terminal.remoto.net que estará escuchando en el puerto 8080:
[hell@terminal.remoto.net] $ netstat -an | grept LISTEN
tcp 0 0 127.0.0.1.8080 *.* LISTEN
tcp 0 0 *.22 *.* LISTEN
[hell@terminal.remoto.net] $
Cada vez que se establezca una conexión al puerto 8080 en terminal.remoto.net, esta conexión, será canalizada por el canal seguro hasta llegar al puerto 80 del equipo alpha.local.net, de esta forma, conseguimos que un equipo ajeno a nuestra red, pueda acceder a nuestro equipo. Pero, ¿qué pasaría si en lugar de a nuestro equipo lo que quisiéramos es que terminal.remoto.com pueda acceder a otro?, usemos el siguiente diagrama para orientarnos:
De nuevo, nos encontramos en alpha.local.net, pero ahora, el servidor está en web.local.net, y lo que queremos es que terminal.remoto.net pueda acceder a el, pero el router sigue impidiendo que terminal.remoto.net se pueda conectar, y sin embargo, si que deja que nosotros desde alpha.local.net podamos conectarnos a terminal.remoto.net. Entonces, un comando como el siguiente sería suficiente:
[hell@alpha.local.net] $ ssh-agent -R 8080:web.local.net:80 terminal.remoto.net
Enter passphrase for key '/home/hell/.ssh/id_dsa':
[hell@terminal.remoto.net] $
Esto indica que un extremo del túnel se corresponde con el puerto 8080 del equipo al que hemos conectado (terminal.remoto.net), y, el otro extremo, es el puerto 80 del equipo web.local.net, así de simple. Al establezcer una conexión en el puerto 8080 de terminal.remoto.net, la conexión viajará por el canal seguro establecido entre el cliente y el servidor de SSH, y después, se establecerá una nueva conexión entre alpha.local.net y web.loca.net para que los datos puedan fluir hasta su destino.
Ejemplo....!!!!!!11
#################################################
Cada vez administro más servidores Linux (ayer se sumaron dos más ubicados en Chicago), por lo que suelo conectarme todo el tiempo por SSH y, obvio, tengo teclear las contraseñas cada vez me conecto a una máquina, algo que realmente se ha vuelto tedioso. Por suerte se puede configurar SSH para que utilice certificados o claves DSA, de tal forma podremos autenticarnos automáticamente en el servidor.
Entonces generaremos las claves DSA usando el protocolo 2, que es el protocolo utilizado y recomendado hoy por hoy. Una de las claves generadas será la “clave privada” que quedará guardada en nuestra máquina y opcionalmente podrá ser protegida con una contraseña. La otra será la “clave pública” que es la que transferiremos al servidor remoto.
Para generar estas claves utilizamos el comando ssh-keygen:
traveler@talita:~$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/traveler/.ssh/id_dsa):
Created directory ‘/home/traveler/.ssh’.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/traveler/.ssh/id_dsa.
Your public key has been saved in /home/traveler/.ssh/id_dsa.pub.
The key fingerprint is:
b4:23:82:5a:19:5b:6f:f3:78:31:fb:f8:45:0b:ed:8f traveler@talita
En la pregunta “Enter file in which to save the key…” hagan enter para que tome el valor predeterminado, lo mismo pueden hacer cuando se les pregunte por la contraseña si no quieren proteger la clave privada con una password.
Una vez terminado el proceso en la carpeta ~/.ssh tendrán un nuevo archivo con la clave pública (id_dsa.pub) y otro con la clave privada (id_dsa). En este punto tendrán que transfierir la clave pública al servidor con el comando ssh-copy-id:
traveler@talita:~$ ssh-copy-id -i .ssh/id_dsa.pub traveler@talita
traveler@talita’s password:
Now try logging into the machine, with “ssh ‘traveler@talita’”, and check in:
.ssh/authorized_keys
to make sure we haven’t added extra keys that you weren’t expecting.
Con esto ssh-copy-id habrá agregado la clave pública al archivo ~/.ssh/authorized_keys del usuario en el servidor remoto y la siguiente vez que nos conectemos la autenticación será automática sin necesidad de ingresar la contraseña nunca más.
#################################################
################QUE ALGORITMO UTILIZAR###################
SSH permite usar los algoritmos RSA y DSA, pero… ¿cuál de ellos nos conviene más?
La diferencia entre ambos reside en los tiempos obtenidos para la generación, firmado y comprobación de las claves públicas. Usando este benchmark (podéis usar cualquier IDE con la última versión del JDK) se obtuvieron los siguientes tiempos:
El algoritmo DSA es más rápido para generar la firma que para verificarla, al contrario de lo que sucede con RSA. Por lo que para realizar la autentificación en nuestro servidor SSH usaremos este último.
Además, si comparamos el tamaño de las llaves generadas por ambos algoritmos, comprobaremos cómo las utilizadas por RSA son superiores a las de DSA.
Dicho esto, usaremos RSA.
Comprobamos si el equipo donde tenemos instalado sshd tiene activada la versión 2 del protocolo SSH y que esté habilitada la opción para utilizar claves RSA. Para ello buscamos las siguientes directivas en el fichero /etc/ssh/sshd_config:
Protocol 2
RSAAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
Para cada usuario que vaya a conectarse, debe existir el directorio /home/usuario/.ssh y en él el archivo authorized_keys. En caso de no ser así deberemos crearlo de forma manual y posteriormente iniciar el servidor.
cd ~
mkdir .ssh
touch .ssh/authorized_keys
sudo /etc/init.d/sshd start
Como antes comentamos, SSH nos permite generar indistintamente claves RSA o DSA (en nuestro caso usaremos la mencionada en primer lugar), creándose para ambas una clave pública y una clave privada.
Dichas claves, pueden generarse en el propio servidor, en el ordenador cliente, o en cualquier otra máquina.
Al final sólo la clave pública debe aparecer en el fichero .ssh/authorized_keys del servidor al que queremos conectarnos.
El usuario interesado en generar el par de claves usará ssh-keygen. En el proceso, se nos pedirá introducir un passphrase, lo que viene a ser una contraseña para poder generar unas claves más fuertes y seguras.
En nuestro caso, vamos a usarla y a explicar posteriormente como indicarle al sistema que sólo nos la pida una vez por sesión, y no cada vez que nos autentifiquemos en el sistema.
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sebas/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sebas/.ssh/id_rsa.
Your public key has been saved in /home/sebas/.ssh/id_rsa.pub.
The key fingerprint is:
63:de:92:6d:00:fa:d9:17:55:45:ce:bc:25:42:8b:4c sebas@TheWorkstation
The key's randomart image is:
+--[ RSA 2048]----+
| E . .oo|
| o o o + |
| . o + . =|
| . . . . .o|
| . S . . |
| . = * . |
| o = = |
| + |
| |
+-----------------+
El anagrama que produce esta versión de ssh-keygen, se denomina randomart y se trata de una representación visual de la huella
digital de nuestra clave, para que sea más legible para el ojo humano y para dispositivos ópticos.
Si lo deseas, puedes usar la herramienta visprint que a través de técnicas de fractales, te permitirá obtener otro tipo de randomart.
Para validar todo este proceso es necesario colocar nuestra clave pública en el servidor donde tenemos pensado autentificarnos.
Existen varias posibilidades de hacerlo, una de ellas es por ejemplo hacer uso del siguiente comando (Cliente):
[usuario1@localhost usuario1]$ ssh usuario @host_remoto \'cat >> .ssh/authorized_keys' < .ssh/id_dsa.pub
Con este comando añadimos directamente la clave al fichero authorized_keys del servidor remoto de forma automática, ahorrándonos así un poco de trabajo.
También podemos usar (Cliente):
$ ssh-copy-id usuario_remoto@host_remoto
Pero ya que estamos haciendo todo con paso firme y decidido, continuemos haciendo las cosas con buen pie. Así que vamos a usar el comando scp, que trae incluido OpenSSH para hacer una transacción de ficheros entre el cliente y el servidor remoto de la forma más segura posible. Así que usaremos la siguiente orden (Cliente)
$ cd ~/.ssh
$ scp id_rsa.pub usuario@host_remoto/
Recuerda que la clave pública debe ser incluída en el fichero ~/.ssh/authorized_keys de cada máquina donde queramos usar dicha autentificación.
Ahora que ya tenemos la clave pública en el servidor, falta añadirla al fichero authorized_keys de éste (algo que comentamos anteriormente que se podría conseguir de forma directa utilizando el primer comando) (Servidor).
$ cd ~/.ssh
$ cat id_rsa.pub >> authorized_keys
$ shred -v --remove id_rsa.pub
Si has realizado correctamente todos los pasos que se han ido indicando, ahora podrás conectarte a tu servidor SSH (Si no tienes uno, visita ésta entrada donde te explicamos cómo montar uno) sin necesidad de identificarte, tan sólo haciendo uso de las claves RSA que has generado.
También puedes incrementar un poco la seguridad modificando las siguientes directivas de tu fichero de configuración sshd_config:
PasswordAuthentication no
PermitRootLogin no
Con las que impedirás la conexión como administrador y la autentificación mediante password para los usuarios.
EJEMPLO.......!
Ubicamos el directorio de configuración
[root@server]# cd /etc/ssh/
[root@server]# ll
total 200
-rwx------ 1 root root 132839 abr 13 18:00 moduli
-rwx------ 1 root root 1827 ago 18 10:52 ssh_config
-rwx------ 1 root root 3450 ago 24 11:12 sshd_config....................archivo para configurar
-rw------- 1 root root 3447 ago 24 12:17 sshd_config.save
-rwx------ 1 root root 672 may 26 10:34 ssh_host_dsa_key
-rwx------ 1 root root 590 may 26 10:34 ssh_host_dsa_key.pub
-rwx------ 1 root root 963 may 26 10:34 ssh_host_key
-rwx------ 1 root root 627 may 26 10:34 ssh_host_key.pub
-rwx------ 1 root root 1675 may 26 10:34 ssh_host_rsa_key
-rwx------ 1 root root 382 may 26 10:34 ssh_host_rsa_key.pub
Editamos el archivo
[root@server]# nano -w sshd_config
# $OpenBSD: sshd_config,v 1.73 2005/12/06 22:38:28 reyk Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/bin:/bin:/usr/bin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options change a
# default value.
#Port 22
#Protocol 2,1
Protocol 2
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 768
# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#RSAAuthentication yes
#PubkeyAuthentication yes
#AuthorizedKeysFile /root/.ssh/authorized_keys
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
# similar for protocol version 2
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
#PasswordAuthentication yes
# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
GSSAPIAuthentication yes
#GSSAPICleanupCredentials yes
GSSAPICleanupCredentials yes
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication mechanism.
# Depending on your PAM configuration, this may bypass the setting of
# PasswordAuthentication, PermitEmptyPasswords, and
# "PermitRootLogin without-password". If you just want the PAM account and
# session checks to run without PAM authentication, then enable this but set
# ChallengeResponseAuthentication=no
#UsePAM no
UsePAM yes
# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#ShowPatchLevel no
#UseDNS yes
#PidFile /var/run/sshd.pid
#MaxStartups 10
#PermitTunnel no
#ChrootDirectory none
# no default banner path
#Banner /some/path
# override default of no subsystems
Subsystem sftp /usr/libexec/openssh/sftp-server
Creamos las llaver privada y Publica RSA
[root@server]# $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/hell/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/hell/.ssh/id_rsa. Your public key has been saved in /home/hell/.ssh/id_rsa.pub. The key fingerprint is: c0:40:50:27:e8:d9:b8:55:d6:a4:5f:af:e5:30:5d:9b [root@server]#$
Revisamos que esten las llaves
[root@server]# cd /root/.ssh/
[root@server]# ll
total 16
-rw------- 1 root root 1675 ago 25 05:35 id_rsa
-rw-r--r-- 1 root root 406 ago 25 05:35 id_rsa.pub
-rw-r--r-- 1 root root 394 ago 24 06:10 known_hosts
Copiamos la llave publica al arcivo authorized_keys en el servidor
[root@server]# cat id_rsa.pub >> authorized_keys
[root@server]# cd /root/.ssh/
[root@server]# ll
total 16
-rw-r--r-- 1 root root 406 ago 25 05:36 authorized_keys.......archivo creado con la llave pub
-rw------- 1 root root 1675 ago 25 05:35 id_rsa
-rw-r--r-- 1 root root 406 ago 25 05:35 id_rsa.pub
-rw-r--r-- 1 root root 394 ago 24 06:10 known_hosts
Copiamos la llave publica al servidor que deseamos acceder
[root@server]# scp -Cpr id_rsa.pub root@00.00.00.00:/root/.ssh/mi_llave.pub
root@00.00.00.00's password:
mi_llave.pub 100% 398 0.4KB/s 00:00
Nos ubicamos en el servidor cliente paras revisar
[root@cliente]# cd /root/.ssh/
[root@cliente]# ll
total 8
-rw-r--r-- 1 root root 406 ago 25 11:27 mi_llave.pub
-rw-r--r-- 1 root root 1177 ago 25 17:43 known_hosts
[root@cliente]#
Copiamos la llave publica al arcivo authorized_keys en el cliente
[root@cliente]# cat mi_llave.pub >> authorized_keys
[root@cliente]# cd /root/.ssh/
[root@cliente]# ll
total 16
-rw-r--r-- 1 root root 406 ago 25 05:36 authorized_keys.......archivo creado con la llave pub
-rw-r--r-- 1 root root 406 ago 25 11:27 mi_llave.pub
-rw-r--r-- 1 root root 394 ago 24 06:10 known_hosts
Eliminamos la llave publica
[root@cliente]# rm -rf mi_llave.pub
Revisamos los Archivos en el cliente
[root@cliente]# cd /root/.ssh/
[root@cliente]# ll
total 8
-rw-r--r-- 1 root root 406 ago 25 11:27 authorized_keys
-rw-r--r-- 1 root root 1177 ago 25 17:43 known_hosts
Ahora nos pasamos a nuestro servidor
vamos a pasar un archivo llamado TDK al servidor cliente remoto
[root@server]# scp -Cpr TDK root@00.00.00.00:/
TDK 100% 1682 1.6KB/s 00:00
como podemos observer no nos ha pedido contraeña para acceder estas llaves son muy utiles para
realizar tareas automaticas...........!
#######################################################
#######################################################
ERROR...:CONEXION........!!!!!!!!!!!!!!
root@localhost:/# ssh root@XX.XX.XX.XX
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
6d:09:a6:69:ac:4e:2c:39:54:7e:9d:e9:11:ec:a2:95.
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending RSA key in /root/.ssh/known_hosts:20................Una Solucion es eliminar la Linea 20 de este archivo
remove with: ssh-keygen -f "/root/.ssh/known_hosts" -R 172.16.0.107
RSA host key for 172.16.0.107 has changed and you have requested strict checking.
Host key verification failed.
root@localhost:/#
Esto se debe a:
Si por algún motivo se reinstala un servidor, al conectar por ssh nos encontraremos que se queja que la identificación ha cambiado. En el caso que no se haya tocado nada puede ser que alguien este intentando suplantar el servidor con un ataque man-in-the middle.
Si sabemos que no se trata de un ataque, sino que hemos sido nosotros que hemos reinstalado el sistema, podemos eliminar del known_hosts la identificación antigua mediante ssh-keygen:
y se resuelve:
$ ssh-keygen --help ...................nos enseñara las opciones
$ ssh-keygen -R........................elimina los known_hostd
$ rm /root/.ssh/known_hosts
$ ssh -l
o si te conectas desde una cuenta de usuario:
$rm /home/usuario/.ssh/known_hosts
hasta Pronto....!!!
######################################################################################
Enviar Mensage por SSH
# w
# echo "Esto es un mensaje de prueba" > /dev/tty2
# echo "Esto es un mensaje de prueba" > /dev/pts/2
Si deseamos ejecutar programas gráficos que utilicen el entorno gráfico X11 (XFree86) sin tener que instalar el programa en local es posible hacerlo mediante el ssh.
Los programas podran residir tanto en otros equipos Mac OS X como en cualquier UNIX o Linux que soporte este entorno.
Para que funcione lo aquí expuesto hay que asegurarse que está instalado el X11.
Para el X11 el cliente es la máquina remota a la que me conectaré.
Aquí se comenta el proceso a seguir en un Mac OS X, pero en cualquier otro sistema (UNIX, Linux) puede diferir.
El cliente deberá tener configurado el X11Forwarding
para lo cual, habrá que revisar y, si procede, modificar dos ficheros /etc/ssh_config
y /etc/sshd_config
.
ssh_config
Debe modificarse la línea de código
#ForwardX11 no
por
ForwardX11 yes
sshd_config
Debe modificarse la línea de código
#X11Forwarding no
por
X11Forwarding yes
Además habrá que decirle dónde debe redireccionar la salida de pantalla y eso lo haremos con el comando:
export DISPLAY=localhost:10.0
Para arrancar el servicio únicamente deberemos dirigirnos a Preferencias del Sistema / Compartir y activar Sesión remota.
Para el X11 el servidor es la máquina donde estoy trabajando.
Para conectarse al cliente se debe ejecutar el programa X11 (/Aplicaciones/Utilidades/
) e introducir el comando:
ssh -X usuario@maquinacliente
A continuación nos pedirá la contraseña y, tras introducirla, nos permitirá trabajar como si estuviesemos en la máquina cliente.
Si todo ha funcionado correctamente podremos comprobar que funciona con un programa sencillo como:
/usr/X11R6/bin/xlogo
Tomado de: http://mcuser.uv.es/es/art.php?art=ard&pag=rx11.html
Atentamente:
Franklin Campo