¿Qué es SSH?
SSH o Secure Shell, es un protocolo de comunicaciones que proporciona seguridad criptográfica, mediante el intercambio de claves pública y privada, cuando nos conectamos a un servidor para iniciar una sesión o transfereir archivos por SFTP o SCP.
Los comandos SSH, SFTP y SCP utilizan el mismo puerto de comunicaciones, que es el 22.
De hecho, SSH se ha convertido en el estándar de conexión a cualquier servidor UNIX, precisamente, para que los hackers no puedan espiar los datos que enviamos a los servidores a los que nos conectamos, como nuestro usuario y contraseña, por ejemplo.
El proceso de autenticación es el paso final antes de que se le otorgue acceso a un usuario. De manera predeterminada, los usuarios se autentican con una contraseña, pero es posible deshabilitar la autenticación de contraseña. El usuario ingresa un nombre de usuario y una contraseña y las credenciales pasan a través de un túnel cifrado simétricamente. Aunque las contraseñas están encriptadas, no son un método de autenticación seguro porque los bots pueden forzar fácilmente a los brutos. Una mejor manera de asegurar la conexión es usar pares de claves SSH.
El protocolo SSH proporciona un fuerte cifrado y protección de integridad. Los datos se cifran utilizando algoritmos de cifrado fuertes estándar de la industria. También tiene mensajes para garantizar que sean auténticos. Un HMAC es un tipo de criptografía que garantiza que los datos no sean manipulados por un tercero. El software SSH maneja la generación de claves, compartir claves públicas, emitir desafíos y controlar el acceso.
Podemos invocar SSH a través de la línea de comandos (comando ssh) o a través de programas especializados que aportan entorno gráfico y una serie de herramientas adicionales.
Antiguamente, nos conectábamos a los servidores mediante telnet o rlogin, pero estos protocolos no estaban cifrados y, por lo tanto, eran vulnerables a un ataque.
En Linux, el demonio (daemon) SSH se arranca con el boot del sistema y está configurado como servicio.
Ejemplo en Centos 7:
# ps -ef |grep ssh |grep -v grep
root 965 1 0 Sep23 ? 00:00:17 /usr/sbin/sshd -D
root 30020 965 0 10:18 ? 00:00:00 sshd: centos [priv]
centos 30022 30020 0 10:18 ? 00:00:00 sshd: centos@pts/0
# systemctl list-unit-files |grep -i ssh
sshd-keygen.service static
sshd.service enabled
sshd@.service static
sshd.socket disabled
#
Si el servicio SSH está arrancado y disponemos de un usuario y contraseña, podremos utilizar un cliente SSH para conectarnos al servidor o utilizar el comando SSH.
# ssh 192.168.1.2
root@testserver's password:
#
¿Cómo habilitar el servicio de SSH?
En distribuciones de Linux basadas en RedHat, habilitaremos y arrancaremos el servicio de SSH de la siguiente manera:
systemctl enable sshd
systemctl start sshd
Conexión SSH con Timeout
Establecer un timeout a una conexión SSH es una buena práctica cuando creamos scripts o jobs de ansible automatizados que se van a ejecutar en cientos de servidores. Si no establecemos un timeout, el script se quedará colgado cuando en uno de los servidores falle la conexión y el proceso de SSH se quede a la espera de respuesta indefinidamente.
Para establecer un timout en una conexión SSH, lo haremos de la siguiente manera:
[root@server1 ~]# ssh -o ConnectTimeout=10 HostnameInventado
ssh: connect to host hostnameinventado port 22: Connection timed out
[root@server1 ~]#
Creación de una relación de confianza SSH entre dos servidores para acceder sin contraseña
A los administradores de sistemas y aplicaciones les puede ser muy útil conectarse por SSH a un servidor remoto sin que éste pida usuario y contraseña.
Para ello podemos crear una relación de confianza entre un usuario y servidor origen y un usuario y servidor destino.
Lo primero que tenemos que hacer es crear un fichero de intercambio de claves:
[usuario1@noname00 ~]$ ssh-keygen -t rsa Generating public/private rsa key pair.
Enter file in which to save the key (/home/usuario1/.ssh/id_rsa):
Created directory '/home/usuario1/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/usuario1/.ssh/id_rsa.
Your public key has been saved in /home/usuario1/.ssh/id_rsa.pub.
The key fingerprint is:
1f:2a:14:34:4c:fb:22:37:c4:45:79:1f:d6:6f:c3:11 usuario1@noname00 The key's randomart image is:
+--[ RSA 2048]----+
| o.. |
| o +.. |
| . + .o |
| . E .o |
| =S.+ . |
| oo+o o |
| . .+o . |
| o.... |
| .oo. |
+-----------------+
[usuario1@noname00 ~]$
Con este comando habremos generado el fichero de clave pública y el de clave privada.
[usuario1@noname00 .ssh]$ ls -la
total 12 drwx------ 2 usuario1 usuario1 36 nov 25 19:23 . drwx------ 8 usuario1 usuario1 4096 nov 25 19:23 .. -rw------- 1 usuario1 usuario1 1679 nov 25 19:23 id_rsa
-rw-r--r-- 1 usuario1 usuario1 399 nov 25 19:23 id_rsa.pub
[usuario1@noname00 .ssh]$
El contenido del fichero de la clave pública lo añadiremos al fichero $HOME/.ssh/authorized_keys del usuario y servidor destino. Lo podemos copiar y pegar, directamente o utilizar el comando ssh-copy-id de la siguiente manera:
ssh-copy-id -i ~/.ssh/id_rsa.pub root@hostname
Una vez creada la relación de confianza ya podemos entrar al servidor de destino sin que nos pida contraseña. Por ejemplo:
[usuario1@noname00 .ssh]$ ssh usuario2@test2
[usuario2@test2 .ssh]$
Evitar que SSH pregunte por la autenticidad del servidor
La primera vez que establecemos una conexión SSH contra un servidor remoto, SSH nos avisa de que la autenticidad del servidor todavía no ha sido establecida:
-bash-4.1$ ssh lremdot1
The authenticity of host 'lremdot1 (10.49.0.186)' can't be established.
RSA key fingerprint is 7d:56:4e:b0:8f:42:4d:01:40:0b:f0:67:10:82:8b:46.
Are you sure you want to continue connecting (yes/no)?
Para evitar que SSH nos haga esta pregunta, algo que viene bien cuando administramos cientos de servidores y tenemos playbooks con Ansible para administrarlos, tenemos que configurar el siguiente fichero:
[root@lhpilox01 .ssh]# pwd
/root/.ssh
[root@lhpilox01 .ssh]# cat config
Host *
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null
[root@lhpilox01 .ssh]#
Copiar ficheros por SCP a un servidor remoto
El comando scp copia ficheros o directorios completos de manera recursiva de un servidor origen a un servidor y path destinos de manera completamente cifrada. La sintaxis es muy sencilla:
- Copia de ficheros: scp -p fichero usuario@servidor_remoto:PATH
- Copia recursiva de directorios: scp -pr fichero usuario@servidor_remoto:PATH
# scp -p vgdisplay.txt servidor2:$PWD
vgdisplay.txt 100% 16KB
16.3KB/s 00:00
#
Exportar una variable de entorno por SSH
Es posible que necesitemos exportar el valor de una variable al servidor remoto para que pueda funcionar correctamente la ejecución de un script en bash. Lo haremos de la siguiente manera:
ssh remote_server -n “export PATH=$PATH:/scripts; mi_script.sh”
Creación de un túnel SSH
Los túneles SSH se utilizan para conectarnos a una IP y un puerto remotos a los que no tenemos acceso directo pero sí mediante un servidor intermedio.
Hace tiempo creé el siguiente manual para un equipo de aplicaciones de mi empresa que me servirá:
Escenario
- Queremos acceder desde nuestro PC local hacia una IP y puerto remota a la que no tenemos acceso directamente.
- Servidor destino:
- caifor.es
- IP fija del servidor destino: 172.23.66.42
- IP NAT del servidor destino, al que solamente tenemos acceso desde la estación de salto sshgreiemea01.omc.hp.com: 29.80.0.22
- IP virtual del servicio al que realmente queremos acceder (ubicada en el servidor secaiasp05): 172.23.66.55:7009.
- Desde la estación de salto no hay conexión directa a la IP y puerto del servicio. Solamente tenemos conexión SSH.
Creación del primer túnel
- Nos conectamos por SSH a la estación de salto.
- Desde la estación de salto nos conectamos al servidor de destino por SSH, pero redirigimos el puerto del servicio (172.23.66.55:7009) al puerto local de la estación de salto 1234.
-bash-3.2$ netstat -an |grep 1234
-bash-3.2$ ssh -L 1234:172.23.66.55:7009 secaiasp05.caifor.es
Password:
- Si volvemos a entrar en la estación de salto, podremos comprobar que ahora hay escuchando el puerto 1234.
-bash-3.2$ netstat -an |grep 1234
tcp 0 0 127.0.0.1:1234 0.0.0.0:* LISTEN
tcp 0 0 ::1:1234 :::* LISTEN
-bash-3.2$
Creación del segundo túnel
Como desde nuestro PC local no tenemos acceso al puerto 1234 de la estación de salto, tenemos que crear un segundo túnel. Lo haremos con nuestro cliente de SSH que utilizamos actualmente.
En este ejemplo, abriremos el puerto 1234 en nuestro PC local, para que se conecte al puerto 1234 de la estación de salto (que está redirigido a la IP y puerto del servicio al que queremos acceder 172.23.66.55:7009).
Lo haremos de la siguiente manera. En este caso, utilizo el cliente de ssh SecureCRT.
A continuación, abriremos nuestro navegador local para acceder al servicio mediante la URL: http://localhost:1234/console (en realidad, el servicio está sirviendo en el servidor mediante la URL http://172.23.66.55:7009/console).
Túnel SSH con Putty
Si usamos Putty, uno de los programas más utilizados para conexiones SSH, en vez de SecureCrt, crearemos el túnel desde el menú «Tunnels», tal y como muestro en la siguiente captura de pantalla:
Túnel SSH con Moba XTerm
Moba XTerm es otro de los clientes SSH más utilizados. El mismo túnel que hemos creado previamente con Putty, lo haríamos de la siguiente manera con Moba XTerm:
Probemos un túnel SSH con Moba Xterm al puerto 22 para conectarnos a un servidor final al que sólo podemos conectarnos a través de una estación de salto:
La conexión SSH desde mi portátil a localhost:22 llega al servidor de destino:
Evitar la desconexión de una sesión SSH en Linux
Es una buena práctica configurar reglas de firewalls para eliminar las conexiones «zombies», por ejemplo, cada 2h, ya que no sería normal establecer una sesión durante tanto tiempo sin que se envíe nada de tráfico. De esta manera, cuidamos de los recursos de red del entorno y liberamos los sockets que no están en uso.
Sin embargo, puede ser útil en algunos casos establecer un parámetro de Keep alive para enviar algo de tráfico cada cierto tiempo para que no se nos caiga la conexión. Esto lo podemos hacer tanto del lado del servidor SSH como del cliente.
Configuración del KeepAlive para conexiones SSH desde el cliente MoBaXTerm
Ejemplo de activación del keepAlive desde el cliente SSH Moba XTerm:
Configuración de KeepAlive desde el servidor SSH en Linux
En cuanto a la configuración del servidor SSH, en Linux RedHat configuraremos los siguientes parámetros:
[root ~]# grep -i alive /etc/ssh/sshd_config
TCPKeepAlive yes
ClientAliveInterval 60
ClientAliveCountMax 5
[root ~]#
Una vez configurados, reiniciaremos el servicio de SSH.
El parámetro ClientAliveInterval 60 se refiere a que se enviará tráfico cada 60 segundos para que no muera la sesión SSH.
Conexión de SSH a través de un proxy
Si queremos utilizar SSH detrás de un proxy, lo podremos hacer de la siguiente manera:
RHEL6
[root@server1 ~]# ssh -o ConnectTimeout=3 -o ProxyCommand='/usr/bin/nc -X connect -x 192.168.47.162:8080 %h %p' usuario@169.50.223.146
usuario@169.50.223.146's password:
[root@server1 ~]#
RHEL7
[root@server1 ~]# sftp -o "ProxyCommand nc --proxy 192.168.47.162:8080 %h %p" usuario@169.50.223.146
usuario@169.50.223.146's password:
Connected to 169.50.223.146.
sftp> ls -la
drwxr-xr-x 3 0 0 4096 Oct 18 2017 .
drwxr-xr-x 3 0 0 4096 Oct 18 2017 ..
drwxr-xr-x 5 1001 100 4096 Feb 22 2019 data
sftp>
En el ejemplo anterior, la IP y puerto del proxy son: 192.168.47.162:8080.
Permitir conexiones SSH con root solamente desde una IP origen
Si solamente queremos permitir el acceso con root desde una IP origen, editaremos el fichero /etc/ssh/sshd_config, añadiendo las siguientes directivas:
PermitRootLogin yes
AllowUsers root@10.48.0.29
Pero esta opción solamente va a permitir conexiones para el usuario root del servidor con IP 10.48.0.29. Así que no sería la opción correcta para la mayoría de los casos, ya que el resto de usuarios no se podrán conectar.
Si lo que queremos es que cualquier usuario pueda conectarse por SSH al servidor pero con root solamente desde una IP concreta, la solución pasa por configurar las siguientes directivas:
PermitRootLogin no
### Resto de directivas SSH ###
Match host 10.48.0.29
PermitRootLogin yes
Ejecutar un script local en un servidor remoto con SSHPASS
Pongamos que tengo un script en un servidor local que quiero que se ejecute en un servidor remoto en el que no existe este script:
# ll
total 4
-rwxr--r-- 1 hpddpers uxsup3 249 May 4 10:31 luns.sh
#
Para hacerlo, ejecutaré el siguiente comando:
Mi pasión por la tecnología me lleva constantemente a explorar las últimas tendencias y aplicaciones, buscando siempre formas de implementar soluciones innovadoras que mejoren la eficiencia. En puerto53.com comparto contenido valioso para ayudar a otros profesionales y entusiastas de la informática a navegar y dominar el complejo mundo de la tecnología. Mi especialidad en Linux RedHat.
Más sobre mí en el este enlace,