SSH o Secure Socket Shell permite ejecutar una shell en un servidor remoto, de forma que dicha shell se pueda manipular a través de una red, utilizando para ello un canal TCP. Además, la interacción con la shell debe de hacerse de forma segura. Como los canales TCP no proporcionan una comunicación segura, es necesario añadir una capa de seguridad adicional que cifre los datos. Estas son las funcionalidades más relevantes de SSH. En resumen, mediante un cliente SSH podremos acceder a las máquinas sobre las que vayamos a operar de forma segura y eficiente.
En los siguientes apartados se introducirán algunos aspectos importantes relacionados con SSH y su relación con el acceso a máquinas virtuales creadas en Google Cloud Engine.
La encriptación se basa en el cifrado con una clave de un mensaje cuyo contenido se quiere proteger. SSH utiliza tanto el cifrado simétrico como el cifrado asimétrico.
En el cifrado simétrico se utiliza la misma clave tanto para el cifrado como el descifrado. Esto significa que la clave debe ser secreta (conocida solo por el emisor y el receptor). El mayor problema de este cifrado es cómo puede hacer llegar el emisor al receptor la clave de forma segura.
En el cifrado asimétrico se utilizan dos claves relacionadas entre sí: una privada (secreta) y otra pública. Las claves tienen la propiedad de que un mensaje cifrado por una determinada clave pública solo puede ser desencriptado utilizando la correspondiente clave privada (y si es encriptado con la clave privada, solo puede desencriptarse con la pública).
Esto permite que el emisor pueda utilizar la clave pública del receptor para encriptar el mensaje y solo éste pueda desencriptarlo. Por otro lado, si el propietario de la clave privada la utiliza para cifrar un mensaje, el destinatario (si la puede desencriptar con la clave pública del emisor) está identificando y autenticando al remitente.
Aunque el cifrado asimétrico soluciona el intercambio de claves entre los participantes en la comunicación, tiene varios problemas en comparación con el cifrado simétrico, como un mayor tamaño de los mensajes codificados y necesidad de un mayor tiempo de proceso.
El protocolo SSH determina la secuencia de eventos para lograr una comunicación segura entre dos host. Resumidamente esta consiste en:
El servidor se identifica ante el cliente con una llave (o clave) de host única. La primera vez que se conecta el cliente la llave no existirá y será necesario que la valide el cliente (este es un paso crítico y debería asegurarse, quizás por otros medios, que la llave es correcta). Esta llave se guarda en el cliente y en sucesivas ocasiones vale para comprobar la identidad del servidor. En ciertos casos (por ejemplo, cambios en la máquina servidora) puede variar esta llave y es necesario eliminar la guardada para aceptar la nueva.
La orden ssh es un cliente SSH disponible en sistemas UNIX/Linux (hay múltiples clientes de SSH, por ejemplo PuTTY para Windows). La máquina que actué como servidora debe estar ejecutando sshd
(SSH Daemon) y debe de poder escuchar las conexiones TCP/IP en el puerto 22, que es el que utiliza por defecto SSH.
Su sintaxis básica es:
ssh user@hostname
donde hostname
es la máquina remota a la cual se desea conectar y user
es el usuario de la máquina remota con el que se conectará (debe, por tanto, existir en dicha máquina).
La orden ssh
tiene múltiples opciones y utiliza dos ficheros de configuración. Los datos de configuración se obtienen por este orden de precedencia:
~/.ssh/config
)/etc/ssh/ssh_config
)El archivo de configuración de usuario se describe más adelante en este documento.
Para generar un par clave pública/privada se puede hacer:
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/ogarcia/.ssh/id_rsa):
Se pueden dar un nombre concreto a la clave, incluso tener más de una, pero la clave que se usa siempre por defecto es id_rsa
.
Esta orden genera dos archivos, uno con la clave pública (.pub
) y otro con la clave privada. Es importante recordar que debemos hacer una copia de seguridad de la clave privada, ya que si la perdemos (o simplemente nos cambiamos de máquina) no podremos acceder a los recursos (las máquinas virtuales) a los que dicha clave da acceso.
$ ls -l ~/.ssh
-rw-------@ 1 ogarcia staff 1799 Feb 15 2019 /Users/ogarcia/.ssh/id_rsa
-rw-------@ 1 ogarcia staff 401 Apr 21 2016 /Users/ogarcia/.ssh/id_rsa.pub
También es importante usar el modo 400
en ambos archivos, ya que configuraciones de seguridad más relajadas hacen que ssh
se niegue a usar dichas claves por inseguras.
Las claves se pueden usar de dos formas: de forma global para todas las máquinas que pertenezcan a un proyecto, o de forma individual para una máquina concreta.
Para usar la clave de forma global debemos acceder al proyecto de Google Cloud -> Compute Engine -> Metadatos
En la barra de pestañas, arriba a la izquierda, accedemos a la opción Claves ssh
. Podemos añadir la clave que generamos con ssh-keygen
pulsando el botón de Añadir Clave.
La clave que vamos a añadir es, por supuesto, la clave pública. Como recomendación, y ante la duda de qué clave utilizar en cada ocasión, si la pública o la privada, siempre hay que tener en cuenta que la clave privada nunca debe salir de nuestro ordenador (y mucho menos para ponerla en Google Cloud), debemos mantenerla segura y en secreto. Por su parte, la pública puede difundirse como su nombre indica, públicamente.
La clave pública tiene el siguiente formato:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvfGpt7F7eCFfJJnSHOAY1TVGHw/T2WAHHw3sPK2/KUR90N4n6liqpm29ScXLTFaJX6m9dswblMej1LjEQO5FYBx7QhVJoDjascCs9ikxHGlRPER8lgq/DJGywR51ihpEM2CjQ6xk61/9tsl/89Bh4FwdhqydS0nvHxLZ3jhMLiDyFH/7kNfNufsrgd3neQfqdvRJnl8W7MPahVWrcqWHQMFQ19yX2A5uDWqUmZVxxsvaDzocDb5On3tV7+kxmIjiKEMV5jhz7e0fJfQfASFKF13rAQVCZNMrW/er7R6KlTxqnCF3BHu3OCOoyHu+9NB3AfPhon/PRObFLZP/4X7iuw
== o.garcia@everywhere
Simplificando mucho su formato (más detalles en RFC 4716 - The Secure Shell (SSH) Public Key File Format), la primera parte es la cadena literal ssh-rsa
, seguida de la clave en sí, y por último un campo de comentario, en el que generalmente se pone un email con objeto de identificar la clave. No obstante, para GCE, esta dirección de email tiene un significado especial: el nombre de usuario de dicha dirección (el nombre a la izquierda de la arroba) lo emplea como nombre de usuario en las máquinas de GCE. Por lo tanto, a la hora de pegarlos en la consola tenemos que segurarnos de que dicha dirección tiene el campo de usuario que nosotros queramos.
Para hacer más cómodo el uso de ssh con muchas máquinas implicadas podemos utilizar un archivo de configuración que debe colocarse en ~/.ssh/config
. Es muy posible que este archivo no exista y deba crearse desde cero.
Host operaciones
Hostname 35.234.81.207
User ogarcia
ForwardAgent yes
IdentityFile ~/.ssh/id_rsa
En el ejemplo anterior, operaciones
es un identificador arbitrario, fácil de recorar para nosotros, ya que lo utilizaremos para hacer, por ejemplo: ssh operaciones
, y por lo tanto da nombre a una máquina concreta. La directiva Hostname
sirve para indicar cual es la IP o el nombre DNS de la máquina, User
el nombre del usuario con el que nos conectaremos (y que tiene que coincidir con el especificado en la clave pública subida a google cloud) y por último IdentityFile
indica dónde se encuentra la clave privada que hay que usar para conectar con la máquina. La directiva ForwardAgent yes
permite activar una funcionalidad denominada Agent Forwarding de la que hablaremos más adelante.
Hay un caso de uso de las conexiones ssh que merece atención. Supongamos que podemos acceder desde mi máquina local ssh-agent
. Este agente recuerda nuestra clave privada y acepta peticiones de cifrado de otros agentes. Cuando el agente de
scp
y rsync
Para transferir información de forma sencilla se puede utilizar scp
, que funciona como su equivalente cp
pero permite especificar que el origen y/o el destino sean máquinas remotas accesibles mediante SSH. En el caso que ambas máquinas, origen y destino, sean remotas es importante tener en cuenta que la transferencia de datos se hace directamente entre ellas, es decir, que el origen deber tener visible el destino y tener acceso a él.
El formato para especificar el origen o destino, cuando es local es el mismo que si usáramos cp. En el caso remoto se especifica de la siguiente forma: usuario@host:path
. El usuario
es un usuario con acceso a la máquina host
, y con permisos para leer el archivo indicado en el path
.
La orden scp
soporta la expansión del *
pero si queremos copiar asimismo directorios es necesario poner el modificador -r
(recursive).
Otra forma más eficiente, en la mayoría de los casos, para transferir información es utilizando rsync
. La operativa básica es idéntica a la de scp
, pero rsync
comprueba si el archivo que vamos a transferir existe ya en el destino. En caso negativo simplemente lo copia como haría scp
, pero en caso afirmativo comprueba primero si ambos, origen y destino, difieren, y evita transferir datos si son iguales. Se puede decir que rsync
mantiene origen y destino sincronizados, de ahí su nombre. Los flags de invocación más interesantes son:
-a
, --archive
, indica modo de archivado, que equivale a -rlptgoD
, lo que significa que debe copiar directorios si los hubiera, transferir archivos que representen manejadores de dispositivo, respetar enlaces simbólicos, fechas de modificación, información de pertenecia a usuarios y grupos y permisos de acceso.-z
, --compress
, indica que se debe comprimir la información en tránsito-v
, --verbose
, indica que se debe informar del progreso de la sincronización (ver también -P
--partial-progress
)--delete
, indica que se deben borrar archivos en el destino que hayan sido eliminados en el origen.-e
en el caso de que se quiera utilizar otro tipo de shell que no sea ssh
Los túneles SSH permiten desviar el tráfico de puertos TCP, tanto locales como remotos, a través del socket que da servicio al propio ssh de forma segura. Dicho de otra forma, el canal de comunicaciones que se establece entre la máquina cliente y la máquina servidor se puede utilizar para enviar más datos que los propios que se mandan y se reciben de la shell, por ejemplo los dirigidos a un determinado puerto TCP. Dependiendo si este puerto es el de la máquina cliente o de la máquina servidora se habla de túneles locales o remotos respectivamente.
Permite dirigir el tráfico a un puerto TCP de la máquina cliente a cualquier puerto de cualquier máquina accesible por la máquina servidora. La sintaxis para indicar este tipo de túneles es la siguiente:
ssh -L PUERTO_LOCAL:MAQUINA_REMOTA:PUERTO_REMOTO
Por ejempo, desde nuestra máquina podemos hacer una petición GET a ip.jsontest.com
para obtener nuestra dirección IP haciendo:
local$ curl https://api.my-ip.io/ip.json
{"success": true, "ip": "34.142.120.59", "type": "IPv4"}
Ahora vamos a hacer que la llamada la haga nuestra máquina de operaciones en google. Para ello abrimos un túnel local a nuestro puesto 8787
(arbitrario).
ssh -L 8787:api.my-ip.io:443 operaciones
Esta orden abrirá una conexión con la máquina operaciones como si fuera una conexión ssh habitual, y de hecho lo es. Manteniendo esa sesión abierta, en otra ventana de terminal, en nuestra máquina local hacemos un intento de conexión al puerto 8787 de la siguente forma:
curl --insecure https://localhost:8787/ip.json
{"ip": "35.228.71.152"}
ASO-GISI
ASO-GIT
2022-2023