SSH: Claves, Config y Fallos Reales

SSH es simple una vez que dejas de tratarlo como una caja mágica de login. Un cliente contacta un servidor, verifica la identidad del servidor y luego demuestra la identidad del usuario. La mayoría de los fallos te dicen exactamente cuál de esas etapas se rompió.

🎙️ Publicado y grabado: ·

01El modelo de claves: candado y prueba

Tu clave privada se queda en tu máquina. La clave pública puede copiarse libremente a servidores. Durante el login, el servidor te pide que demuestres posesión de la clave privada; la clave privada no se sube. En el servidor, una línea en ~/.ssh/authorized_keys otorga acceso a una clave pública para esa cuenta.

# Make a modern key pair; use a passphrase.
ssh-keygen -t ed25519 -a 100 -C "laptop-2026"

~/.ssh/id_ed25519       PRIVATE — never send this
~/.ssh/id_ed25519.pub   PUBLIC — install this on servers

# Show the public key safely:
cat ~/.ssh/id_ed25519.pub
Mi postura
No envíes claves privadas por email, no reutilices una clave para todo el equipo ni quites la passphrase por comodidad. Genera una clave por persona y dispositivo. Revocar entonces significa borrar una línea pública, no coordinar un reemplazo de secreto a nivel de empresa.

02Conéctate una vez, luego pregunta al modo verbose

Un destino SSH tiene cuatro datos: usuario, host, puerto e identidad. Los valores por defecto ocultan tres de ellos, lo cual es agradable hasta que el default equivocado gana. Cuando una conexión falla, ejecuta el mismo comando con un -v. Léelo por etapa: conexión de red, verificación de host-key y luego ofertas de autenticación.

ssh [email protected]
ssh -p 2222 [email protected]

# Diagnostic view; -vvv is usually noise until -v is insufficient.
ssh -v -p 2222 [email protected]

# Useful lines:
debug1: Connecting to server.example.com [203.0.113.10] port 2222.
debug1: Server host key: ssh-ed25519 SHA256:...
debug1: Offering public key: /home/alice/.ssh/id_ed25519

Sé preciso con el usuario remoto. Tu nombre de usuario en el portátil no es evidencia de que la cuenta del servidor tenga el mismo nombre. Las imágenes cloud suelen esperar ubuntu, ec2-user u otra cuenta provisionada.

03Corregir Permission denied (publickey)

Este mensaje exacto significa que la ruta de red y el servicio SSH funcionaron. La autenticación no. No depures firewalls ahora. Confirma el usuario remoto, mira qué clave ofrece el cliente, fuerza la clave prevista, y luego verifica que su clave pública correspondiente está instalada para esa cuenta exacta del servidor.

[email protected]: Permission denied (publickey).

# 1. Does verbose output say "Offering public key"?
ssh -v [email protected]

# 2. Force the intended identity and ignore surprise keys:
ssh -o IdentitiesOnly=yes -i ~/.ssh/work_ed25519 [email protected]

# 3. Compare fingerprints, not filenames:
ssh-keygen -lf ~/.ssh/work_ed25519.pub
# On server console:
ssh-keygen -lf /home/alice/.ssh/authorized_keys
Orden de reparación
Usuario incorrecto primero, clave ofrecida incorrecta segundo, entrada faltante en authorized_keys tercero, permisos cuarto, política del servidor último. Regenerar claves al azar destruye evidencia y a menudo te deja con dos claves incorrectas en vez de una.

04Permisos: privado significa privado

OpenSSH rechaza una clave privada legible por otros usuarios. El servidor también puede ignorar authorized_keys si su directorio o archivo es escribible por las personas equivocadas. Corrige la propiedad antes que los modos; chmod no puede reparar un archivo propiedad de root.

WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for 'id_ed25519' are too open.

# Client:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

# Server, run for the target account:
chown -R alice:alice /home/alice/.ssh
chmod 700 /home/alice/.ssh
chmod 600 /home/alice/.ssh/authorized_keys

En Windows, usa la configuración de Seguridad del archivo o icacls para eliminar el acceso heredado de usuarios no relacionados. Copiar números de modo Unix en PowerShell no es una solución multiplataforma; la regla es que solo el propietario debe poder leer la clave privada.

05La identificación del host cambió

La host key identifica al servidor. Una clave cambiada puede ser una reconstrucción esperada, una IP reciclada o un atacante interceptando la conexión. La advertencia no puede distinguirlas, así que tu trabajo es verificar. Nunca elimines reflexivamente la advertencia y te reconectes.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
Offending ED25519 key in /home/alice/.ssh/known_hosts:12
Host key verification failed.

# 1. Verify the new fingerprint through a trusted channel:
#    cloud console, provider metadata, or an administrator.
# 2. Remove only that host's stale entry:
ssh-keygen -R server.example.com
ssh-keygen -R "[server.example.com]:2222"
# 3. Reconnect and compare the displayed fingerprint.
Frontera de seguridad
StrictHostKeyChecking=no no es una solución. Cambia una advertencia incómoda por suplantación silenciosa. La verificación toma un minuto; saltarla anula la parte de SSH que te dice qué máquina recibió tus credenciales.

06Connection refused no es un timeout

Estos fallos ocurren antes de la autenticación. "Refused" es una respuesta rápida del destino: el host es alcanzable, pero nada acepta ese puerto, o un firewall lo rechaza activamente. Un timeout significa que las respuestas se pierden o la ruta está rota. Tratar ambos como "SSH está caído" desperdicia la distinción.

ssh: connect to host server.example.com port 22: Connection refused
→ Check port; check sshd is listening; check service state.
ss -ltn | grep ':22'
systemctl status sshd   # some systems name it ssh

ssh: connect to host server.example.com port 22: Connection timed out
→ Check DNS/IP, VPN, routing, security group, firewall allowlist.
ssh -v -o ConnectTimeout=8 [email protected]

Prueba el hostname y puerto reales desde la red real del cliente. Una prueba exitosa desde el propio servidor no demuestra casi nada sobre un firewall de entrada. Una vez que la conexión TCP funciona, entonces vuelve a claves y nombres de usuario.

07Pon los datos estables en SSH config

La línea de comandos es para experimentos. Los hosts estables pertenecen a ~/.ssh/config. Da a las máquinas alias memorables, fija el usuario, puerto e identidad, y usa ssh -G alias para inspeccionar la configuración completamente resuelta cuando la herencia te sorprenda.

Host reports
    HostName reports.internal.example.com
    User alice
    Port 2222
    IdentityFile ~/.ssh/work_ed25519
    IdentitiesOnly yes

Host *.internal.example.com
    ServerAliveInterval 30
    ServerAliveCountMax 3

# Now:
ssh reports
scp results.csv reports:/srv/import/
ssh -G reports | less
Trampa de orden
Para cada parámetro, el primer valor obtenido generalmente gana. Coloca los bloques de host específicos antes de los wildcards amplios. No sigas añadiendo configuraciones duplicadas al final y esperes que la última sobreescriba todo.

08Agents y jump hosts

Un agent mantiene las operaciones de clave desbloqueadas para que no teclees la passphrase en cada conexión. No copia la clave privada. Revisa qué tiene cargado cuando el cliente ofrece las identidades equivocadas. Para redes privadas, usa un jump host en vez de loguearte en un bastión y almacenar tu clave ahí.

# Inspect and load local agent identities:
ssh-add -l
ssh-add ~/.ssh/work_ed25519
The agent has no identities.  # load one, or specify -i

# Reach an internal host through bastion:
ssh -J [email protected] [email protected]

# Config equivalent:
Host private-app
    HostName 10.0.4.12
    User app
    ProxyJump [email protected]

Evita el agent forwarding por defecto. Un host remoto comprometido puede pedirle a tu agent reenviado que firme mientras tu sesión está abierta. ProxyJump enruta la conexión sin exponer el acceso al agent en el bastión y es el mejor valor por defecto.

09Port forwarding sin la confusión

Local forwarding abre un puerto en tu máquina y lo lleva a través de SSH a un destino visible desde el servidor. Lee -L 8080:db.internal:5432 como: escucha localmente en 8080, luego desde el lado remoto alcanza db.internal puerto 5432. Usa -N cuando necesitas el túnel, no un shell.

# Local 15432 → database reachable from gateway
ssh -N -L 15432:db.internal:5432 gateway
psql -h 127.0.0.1 -p 15432 appdb

# Local 8080 → remote service bound to its localhost:3000
ssh -N -L 8080:127.0.0.1:3000 app-server
# Browse http://127.0.0.1:8080

# Fail immediately if forwarding cannot be established:
ssh -N -o ExitOnForwardFailure=yes -L 8080:127.0.0.1:3000 app-server
Default seguro
Enlaza los puertos reenviados a loopback, no a 0.0.0.0. Lo segundo puede exponer una base de datos interna o panel de admin a toda tu red local. Un túnel es transporte privado, no control de acceso automático.

10El checklist de fallos SSH

Clasifica la etapa antes de cambiar nada. Una ejecución verbose más este orden suele ganarle a veinte intentos a ciegas.

□ Did DNS resolve to the expected IP?
□ Is the port correct, reachable, and actually listening?
□ Refused (reachable, closed) or timeout (dropped/unroutable)?
□ Did I verify the server host-key fingerprint?
□ Is the remote username exactly right?
□ Which key does `ssh -v` say it is offering?
□ Does that public key exist in that user's authorized_keys?
□ Are ownership and permissions strict on both sides?
□ What does `ssh -G alias` say after config expansion?
□ Does the agent hold the intended identity?
□ For a tunnel, which machine resolves the destination host?
□ Did I bind only to loopback and use ExitOnForwardFailure?

Mantén las etapas separadas: alcanza el puerto, identifica el servidor, autentica al usuario, luego abre un canal o túnel. Los mensajes de SSH se vuelven útiles en cuanto dejas de tratarlos como un fallo genérico de login.

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.