Saltar al contenido
ecdsa.com
← Todos los artículos

ssh-keygen en 2026: claves, frases de contraseña y agentes

Entre OpenSSH 10.0 y 10.6 cambiaron más valores predeterminados de los que la mayoría tiene presentes: intercambio de claves poscuántico, un tipo de firma híbrido con ML-DSA, más rondas de KDF y los sockets del agente en tu directorio personal. Todos los comandos de abajo se ejecutaron en OpenSSH 10.6p1 y la salida es la real.

Respuesta breve. Ejecuta ssh-keygen -t ed25519 -C "you@host-year" y protege la clave con una frase de contraseña; Ed25519 es el tipo predeterminado desde OpenSSH 9.5. Si tienes una llave de seguridad FIDO2, es preferible -t ed25519-sk (o -t ecdsa-sk cuando el autenticador no admite Ed25519), para que la clave privada nunca esté en el disco. Usa RSA solo en sistemas que no admitan otra cosa, y en ese caso con 3072 bits o más: GitHub rechaza las claves RSA nuevas más pequeñas desde el 14 de octubre de 2026. Carga las claves en el agente con un tiempo de vida limitado (ssh-add -t 8h), no reenvíes el agente a hosts que no controlas (usa ProxyJump) y restringe las claves a destinos concretos con ssh-add -h. En flotas de servidores, sustituye las entradas dispersas de authorized_keys por certificados SSH de corta duración. La protección poscuántica de la sesión ya viene activada: OpenSSH 10 negocia mlkem768x25519-sha256 de forma predeterminada y muestra una advertencia cuando un servidor no puede hacerlo. Merece la pena probar el nuevo tipo de firma híbrido ssh-mldsa44-ed25519 (OpenSSH 10.6), pero todavía no conviene desplegarlo como tu única clave.

Los comandos se ejecutaron en debian:forky-20261005-slim con los paquetes de Debian openssh-client y openssh-server 1:10.6p1-1 el 20 de octubre de 2026. Todas las claves se generaron para este artículo.

Qué tipo de clave elegir

-tQué esCuándo usarla
ed25519 (predeterminado)Ed25519, clave pública de 32 bytes, firmas deterministasCasi siempre
ed25519-sk, ecdsa-skClave FIDO2: el secreto se queda en el autenticador y cada firma requiere un toqueSi tienes una llave de seguridad y el servidor ejecuta OpenSSH 8.2 o posterior
ecdsaECDSA sobre P-256, P-384 o P-521Si una política exige curvas del NIST
rsaRSA, 3072 bits de forma predeterminada desde OpenSSH 8.0Servidores antiguos, dispositivos dedicados, algunos HSM
mldsa44-ed25519Firma híbrida ML-DSA-44 + Ed25519, nueva en 10.6Para probar la autenticación poscuántica

DSA ya no existe: OpenSSH 10.0 (abril de 2025) lo eliminó, «con lo que se completa el proceso de retirada que empezó en 2015». Las claves RSA siguen sirviendo; lo que se desactivó en OpenSSH 8.8 (septiembre de 2021) es el algoritmo de firma ssh-rsa, que calcula el hash con SHA-1. La misma clave RSA firma con rsa-sha2-256 o rsa-sha2-512, y por eso el error del servidor sobre ssh-rsa suele resolverse actualizando el cliente, no sustituyendo la clave. GitHub sigue la misma lógica: eliminará las firmas ssh-rsa el 13 de enero de 2027, tras desactivaciones temporales el 4 de noviembre y el 9 de diciembre de 2026, y desde el 14 de octubre de 2026 solo acepta claves RSA nuevas a partir de 3072 bits.

Tamaños, tal como los escribe ssh-keygen 10.6 (la línea .pub incluye el comentario):

Claves RSA y ECDSA predeterminadas, la híbrida y la clave Ed25519 de la sección siguiente
ssh-keygen -q -t rsa -N '' -f ~/rsa_default
ssh-keygen -q -t ecdsa -N '' -f ~/ecdsa_default
ssh-keygen -q -t mldsa44-ed25519 -N '' -f ~/.ssh/id_mldsa44_ed25519
for f in ~/rsa_default ~/ecdsa_default ~/.ssh/id_ed25519 ~/.ssh/id_mldsa44_ed25519; do
  ssh-keygen -l -f "$f.pub"
  printf '  public key line: %s bytes, private key file: %s bytes\n' "$(wc -c < "$f.pub")" "$(wc -c < "$f")"
done
Salida (OpenSSH 10.6p1)
3072 SHA256:NGv36ZHCwauN4GGrdKSDZPnKTn6nFuLSVRS01/eSXOs alice@59151e7fff6c (RSA)
  public key line: 572 bytes, private key file: 2602 bytes
256 SHA256:4ODqYFVTGSwjx7pfis5ZtZ02PKaSd15alII7RIHPhE8 alice@59151e7fff6c (ECDSA)
  public key line: 180 bytes, private key file: 513 bytes
256 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026 (ED25519)
  public key line: 99 bytes, private key file: 464 bytes
512 SHA256:oqHqur1575V136Khl2P7Gaa6rM+2dPT51B6YfjLSxB4 alice@59151e7fff6c (MLDSA44-ED25519)
  public key line: 1868 bytes, private key file: 3982 bytes

La línea de la clave pública híbrida es 19 veces más grande que la de una Ed25519. Eso importa en los archivos authorized_keys, en los certificados y en cualquier sistema que guarde claves en una columna de base de datos dimensionada para Ed25519. La comparación Ed25519 frente a RSA trata en detalle el par clásico.

Cómo generar una clave

Generar una clave Ed25519 con un comentario que indique dónde está
ssh-keygen -t ed25519 -C "alice@laptop-2026" -N 'correct horse battery staple' -f ~/.ssh/id_ed25519
Salida (OpenSSH 10.6p1)
Created directory '/home/alice/.ssh'.
Generating public/private ed25519 key pair.
Your identification has been saved in /home/alice/.ssh/id_ed25519
Your public key has been saved in /home/alice/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026
The key's randomart image is:
+--[ED25519 256]--+
|     ..o*.....   |
| o  . .=... =.   |
|. o  .. +. + o.  |
| . . . o =. . ...|
|  o   + S ..   ..|
| . . o + B       |
|  . * = * o .    |
|   o E = o.+     |
|      o oo. .    |
+----[SHA256]-----+

-N pasa la frase de contraseña en la línea de comandos solo porque el laboratorio se ejecuta con scripts; en uso interactivo, omítelo y ssh-keygen te la pedirá, así la frase de contraseña no acaba en el historial del shell. El comentario es texto libre guardado en la clave pública: un nombre, la máquina y el año permiten auditar authorized_keys años después. La huella digital (SHA256:…) es lo que los servidores escriben en sus registros, así que apúntala cada vez que des de alta la clave en algún sitio.

Frase de contraseña y rondas de KDF

Sin frase de contraseña, el archivo de clave privada es la clave: una copia de seguridad robada, una imagen de disco de un equipo o una carpeta de sincronización mal configurada la entregan. Con ella, el archivo se cifra con una clave derivada mediante bcrypt_pbkdf. El formato de clave privada de OpenSSH guarda el algoritmo de cifrado, la KDF y sus rondas en un encabezado que cualquiera puede leer sin la frase de contraseña:

kdfinfo.py: leer el cifrado, la KDF y las rondas de una clave privada OpenSSH
"""Print the cipher, KDF and bcrypt rounds from the header of an OpenSSH private key file (openssh-key-v1)."""
import base64
import struct
import sys

text = open(sys.argv[1]).read()
body = "".join(line for line in text.splitlines() if not line.startswith("-----"))
blob = base64.b64decode(body)
magic = b"openssh-key-v1\0"
assert blob.startswith(magic), "not an OpenSSH private key"
pos = len(magic)


def string():
    global pos
    (length,) = struct.unpack(">I", blob[pos : pos + 4])
    value = blob[pos + 4 : pos + 4 + length]
    pos += 4 + length
    return value


cipher = string().decode()
kdf = string().decode()
options = string()
line = f"cipher={cipher} kdf={kdf}"
if kdf == "bcrypt":
    (salt_len,) = struct.unpack(">I", options[:4])
    (rounds,) = struct.unpack(">I", options[4 + salt_len : 8 + salt_len])
    line += f" salt={salt_len} bytes rounds={rounds}"
print(line)
Rondas predeterminadas y, después, lo que cuesta desbloquear con 32, 100 y 500 rondas
python3 kdfinfo.py ~/.ssh/id_ed25519
for r in 32 100 500; do
  ssh-keygen -q -p -a $r -P 'correct horse battery staple' -N 'correct horse battery staple' -f ~/.ssh/id_ed25519 >/dev/null
  s=$(date +%s.%N); ssh-keygen -y -P 'correct horse battery staple' -f ~/.ssh/id_ed25519 >/dev/null; e=$(date +%s.%N)
  printf 'rounds=%s unlock=%.2fs\n' $r $(echo "$e - $s" | bc)
done
Salida (un núcleo arm64 en Docker sobre un Apple M4 Max)
cipher=aes256-ctr kdf=bcrypt salt=16 bytes rounds=32
rounds=32 unlock=0.16s
rounds=100 unlock=0.52s
rounds=500 unlock=2.59s

El valor predeterminado era de 16 rondas hasta OpenSSH 9.4, de 24 desde 9.4 y es de 32 desde 10.6. El trabajo crece de forma lineal con el número de rondas, como señalan las notas de la versión 10.6 («a diferencia de bcrypt(3), que es exponencial»), así que las cifras de arriba escalan de forma predecible: elige el valor más alto cuyo retraso al desbloquear estés dispuesto a aceptar, porque un atacante que haya copiado el archivo paga el mismo precio por cada intento. ssh-keygen -p -a 100 -f ~/.ssh/id_ed25519 vuelve a cifrar una clave existente; si la cargas en el agente una vez por sesión, pagas el retraso una sola vez. Desde 10.6, OpenSSH rechaza las claves con más de un millón de rondas, para que un archivo de clave hostil no pueda bloquear un servicio que lo procese.

Una frase de contraseña protege el archivo en reposo. No sirve de nada una vez que la clave está descifrada en un agente de una máquina comprometida, y ahí es donde entran las claves en hardware.

Claves en hardware: -sk

Las claves ed25519-sk y ecdsa-sk (OpenSSH 8.2 y posteriores) guardan el secreto en un autenticador FIDO2, como una YubiKey o un autenticador de plataforma. El archivo ~/.ssh/id_ed25519_sk contiene entonces solo un identificador (key handle) que el autenticador necesita para reconstruir la clave; sin el dispositivo no sirve de nada. Cada firma requiere la presencia del usuario (un toque) y, con -O verify-required, también un PIN. Las opciones que importan, citadas de ssh-keygen(1):

  • -O resident guarda el key handle en el autenticador, de modo que ssh-keygen -K o ssh-add -K pueden cargarlo en otro equipo. El manual advierte que esto «aumenta la probabilidad de que un atacante pueda usar un autenticador robado», así que combínalo con un PIN.
  • -O verify-required exige la verificación del usuario (por ahora, un PIN) en cada firma; el servidor puede exigirla con la opción verify-required en authorized_keys.
  • -O application=ssh:work separa varias claves residentes en un mismo dispositivo; la cadena debe empezar por ssh:.
  • -O no-touch-required prescinde del toque, y sshd rechaza esas firmas salvo que authorized_keys las permita explícitamente.
  • -O write-attestation=path guarda la atestación del autenticador, que permite a una organización demostrar en el alta que la clave se creó en hardware aprobado.
Alta típica de una clave residente protegida con PIN (requiere un autenticador FIDO2)
ssh-keygen -t ed25519-sk -O resident -O verify-required -O application=ssh:work -C "alice@yubikey-2026"

Este comando no lo ejecutamos: el contenedor no tiene autenticador, y una transcripción sin él solo mostraría el error. Algunos autenticadores antiguos solo implementan P-256; para ellos, usa ecdsa-sk. Las claves de plataforma también funcionan, pero las claves guardadas en el hardware seguro de un equipo portátil tienen sus propias contrapartidas, que se tratan en claves en hardware.

Poscuántico: el intercambio de claves ahora, las firmas después

Las dos mitades de SSH tienen plazos distintos. Las claves de sesión salen del intercambio de claves; si este se rompe más adelante, el tráfico grabado se puede descifrar («cosechar ahora, descifrar después», en inglés harvest now, decrypt later). Las firmas de host y de usuario solo importan en el momento de la conexión: una futura computadora cuántica no puede volver atrás y falsificar un inicio de sesión que ya se produjo. Por eso OpenSSH cambió primero el intercambio de claves:

  • sntrup761x25519-sha512 está activado de forma predeterminada desde OpenSSH 9.0 (2022);
  • mlkem768x25519-sha256, ML-KEM-768 combinado con X25519, es el predeterminado desde OpenSSH 10.0 (abril de 2025) y ahora está especificado en el RFC 10042 (informativo, 2026);
  • desde 10.1, el cliente muestra una advertencia cuando la sesión recurre a un intercambio clásico, y desde 10.6 el servidor lo registra.
ssh -v localhost true, configuración predeterminada en ambos lados (filtrado con grep)
debug1: kex: algorithm: mlkem768x25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: Server host key: ssh-ed25519 SHA256:Qw4tNHnCo8UwS2qNXROrEm8RP+d+ccaVbwAzv8lLX+I
debug1: Offering public key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c agent
debug1: Server accepts key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c agent
Authenticated to localhost ([::1]:22) using "publickey".

Contra un servidor restringido a KexAlgorithms curve25519-sha256,ecdh-sha2-nistp256, el cliente con la configuración predeterminada mostró:

Salida del cliente cuando el servidor no ofrece ningún intercambio de claves poscuántico
** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html

Dos detalles que observamos: el cliente no dice nada cuando eres tú quien restringe KexAlgorithms a un método clásico (la advertencia va dirigida a los servidores), y el servidor registra cada una de esas sesiones, por ejemplo connection from ::1 port 38814 is not using a post-quantum key exchange algorithm: "curve25519-sha256" [preauth]. WarnWeakCrypto no-pq-kex dentro de un bloque Match host silencia el cliente para un host que no puedes corregir, como sugiere openssh.com/pq.html. GitHub anunció mlkem768x25519-sha256 para github.com a partir del 14 de octubre de 2026; el 20 de octubre, nuestro cliente 10.6 lo negoció con git@github.com.

Las firmas son el segundo paso. OpenSSH 10.4 añadió una firma compuesta experimental de ML-DSA-44 y Ed25519; 10.6 la activó con el nombre ssh-mldsa44-ed25519, especificado en el borrador del grupo de trabajo SSHM draft-ietf-sshm-composite-sigs. Las claves creadas con el código experimental de 10.4 deben regenerarse. En el paquete de Debian 10.6, ssh-keygen -A creó ssh_host_mldsa44_ed25519_key junto a las claves de host RSA, ECDSA y Ed25519, y el tipo está al final de los HostKeyAlgorithms predeterminados, así que los clientes siguen eligiendo Ed25519. Pedirlo explícitamente funciona de extremo a extremo:

ssh -v -o HostKeyAlgorithms=ssh-mldsa44-ed25519 -o IdentitiesOnly=yes -i ~/.ssh/id_mldsa44_ed25519 (filtrado)
debug1: kex: host key algorithm: ssh-mldsa44-ed25519
debug1: Server host key: ssh-mldsa44-ed25519 SHA256:UVOUu+csMH8i8Zd/oWzokAGfzRYFetOncVzB4vYeMgQ
debug1: Server accepts key: /home/alice/.ssh/id_mldsa44_ed25519 MLDSA44-ED25519 SHA256:oqHqur1575V136Khl2P7Gaa6rM+2dPT51B6YfjLSxB4 explicit
Authenticated to localhost ([::1]:22) using "publickey".

Las dos mitades firman el mismo mensaje con separación de dominios, y «el fallo de cualquiera de las dos operaciones de verificación DEBE (MUST) provocar el fallo de la verificación de la firma compuesta», así que hoy el híbrido no es más débil que Ed25519. Su precio es el tamaño (una firma de 2484 bytes por autenticación, según el borrador) y la compatibilidad: los servidores, las forjas, los bastiones y las bibliotecas que no conocen el tipo no aceptarán la clave. Genera una, pruébala con los hosts que administras y mantén tu clave Ed25519 registrada en paralelo.

El agente y el reenvío del agente

ssh-agent guarda claves descifradas y firma cuando se le pide; los programas llegan a él a través del socket indicado en SSH_AUTH_SOCK. Desde OpenSSH 10.1, ese socket está en ~/.ssh/agent en lugar de /tmp. Añade las claves con un tiempo de vida limitado para que una sesión olvidada no las mantenga desbloqueadas para siempre:

Iniciar un agente y añadir la clave durante 8 horas (el laboratorio proporciona la frase de contraseña mediante SSH_ASKPASS)
eval "$(ssh-agent -s)" >/dev/null
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
ssh-add -t 8h ~/.ssh/id_ed25519
ssh-add -l
Salida
SSH_AUTH_SOCK=/home/alice/.ssh/agent/s.eaeHp0xOjD.local.660.o5M944i4eW
Identity added: /home/alice/.ssh/id_ed25519 (alice@laptop-2026)
Lifetime set to 08:00:00
256 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026 (ED25519)

AddKeysToAgent en ~/.ssh/config hace lo mismo en el primer uso y acepta un tiempo de vida (AddKeysToAgent 8h) o confirm, que pide confirmación antes de cada firma, como ssh-add -c.

El reenvío del agente (ssh -A, ForwardAgent yes) expone ese socket en el host remoto. ssh_config(5) describe el riesgo sin rodeos: «un atacante no puede obtener material de clave del agente, pero sí puede realizar operaciones con las claves». Cualquiera con acceso root en el host remoto puede iniciar sesión como tú en cualquier sitio donde funcionen tus claves, durante todo el tiempo que sigas conectado. Dos hábitos mejores:

  • Salta en lugar de reenviar. ssh -J bastion target (o ProxyJump bastion en la configuración) ejecuta la segunda conexión desde tu máquina a través de un flujo TCP reenviado; el bastión nunca ve tu agente.
  • Restringe las claves. ssh-add -h (OpenSSH 8.9 y posteriores) vincula una clave a destinos identificados por sus claves de host de known_hosts y, cuando sí reenvías el agente, a saltos concretos (bastion>target).
dest.sh (extracto): una clave que solo funciona con prod-host
ssh-add -h prod-host ~/agent_only_key
ssh -o BatchMode=yes prod-host 'echo signed in on prod-host'
ssh -v -o BatchMode=yes build-host true 2>&1 | grep -iE 'agent|Offering|Permission denied|Authenticated|identity'
Salida (abreviada: se omiten las líneas en las que se prueban los archivos de identidad)
Identity added: /home/alice/agent_only_key (alice@laptop)
signed in on prod-host
debug1: get_agent_identities: bound agent to hostkey
debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities
debug1: Offering public key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:MA2nEhBnMlCkX3pWWgPtff90dRZF9D9k8i2svCUK1II
alice@127.0.0.2: Permission denied (publickey,password).

El agente vinculó la sesión a la clave de host de build-host y después no listó ninguna identidad para ella: la clave existe, pero no para ese destino. El manual es claro sobre el límite: una restricción «no impide que un atacante con acceso a un SSH_AUTH_SOCK remoto lo reenvíe de nuevo y lo use en otro host (aunque solo hacia un destino permitido)».

Certificados en lugar de authorized_keys

Copiar claves públicas en authorized_keys en cada servidor no escala y convierte la revocación en un problema de búsqueda. Un certificado SSH es una clave pública que, junto con una identidad, unos principals, un número de serie y un período de validez, está firmada por una clave de CA. Los servidores confían una sola vez en la CA (TrustedUserCAKeys) y comprueban una lista de revocación (RevokedKeys):

Firmar una clave de usuario por 8 horas, iniciar sesión, revocarla por número de serie y volver a intentarlo (ejecutado como root en el servidor del laboratorio)
ssh-keygen -s /etc/ssh/user_ca -I "alice@example.com 2026-10-20" -n alice -V +8h -z 1042 /home/alice/.ssh/id_cert_user.pub
ssh-keygen -L -f /home/alice/.ssh/id_cert_user-cert.pub
su - alice -c 'ssh -o IdentitiesOnly=yes -o IdentityAgent=none -i ~/.ssh/id_cert_user localhost "echo logged in with certificate"'
echo "serial: 1042" > /tmp/revoke.txt
ssh-keygen -k -u -s /etc/ssh/user_ca.pub -f /etc/ssh/revoked.krl /tmp/revoke.txt
ssh-keygen -Q -f /etc/ssh/revoked.krl /home/alice/.ssh/id_cert_user-cert.pub
su - alice -c 'ssh -o IdentitiesOnly=yes -o IdentityAgent=none -o BatchMode=yes -i ~/.ssh/id_cert_user localhost true'
Salida (sshd se ejecuta con TrustedUserCAKeys /etc/ssh/user_ca.pub y RevokedKeys /etc/ssh/revoked.krl)
Signed user key /home/alice/.ssh/id_cert_user-cert.pub: id "alice@example.com 2026-10-20" serial 1042 for alice valid from 2026-10-20T14:33:00 to 2026-10-20T22:34:33
/home/alice/.ssh/id_cert_user-cert.pub:
        Type: ssh-ed25519-cert-v01@openssh.com user certificate
        Public key: ED25519-CERT SHA256:eVstR5lK6VBztjl2AYyWcv8C6xwNahEEVSrQpe7Y/LE
        Signing CA: ED25519 SHA256:+URM6AMiGUu+gv/gxoQgpOhHP4CUN1fznXWDlVxorbY (using ssh-ed25519)
        Key ID: "alice@example.com 2026-10-20"
        Serial: 1042
        Valid: from 2026-10-20T14:33:00 to 2026-10-20T22:34:33
        Principals: 
                alice
        Critical Options: (none)
        Extensions: 
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc
logged in with certificate
Revoking from /tmp/revoke.txt
/home/alice/.ssh/id_cert_user-cert.pub (alice@ci-runner): REVOKED
alice@localhost: Permission denied (publickey).

sshd registró key ED25519-CERT SHA256:eVst… revoked by file /etc/ssh/revoked.krl. Fíjate en las extensiones predeterminadas: un certificado permite el reenvío del agente y de puertos salvo que lo firmes con -O clear y vuelvas a añadir solo lo necesario (-O permit-pty). Guarda la clave de la CA sin conexión o en un HSM y emite certificados por horas, no por años: con una vida útil corta, la mayoría de las revocaciones dejan de ser necesarias. Los certificados de host (-h al firmar, @cert-authority en known_hosts) eliminan de la misma forma la pregunta de confianza en el primer uso.

Rotación de claves

  • Claves de usuario. Genera la clave nueva, añade su clave pública junto a la antigua en todas partes (servidores, forjas, secretos de CI), conéctate con -i new_key -o IdentitiesOnly=yes para comprobar que funciona y, después, elimina la línea antigua. Un comentario con fecha te dice qué línea es la antigua.
  • Claves de host. UpdateHostKeys está activado de forma predeterminada desde OpenSSH 8.5 (salvo que sobrescribas UserKnownHostsFile o actives VerifyHostKeyDNS): tras la autenticación, el servidor anuncia todas sus claves de host y el cliente registra las nuevas, de modo que un servidor puede publicar una clave de reemplazo antes de retirar la antigua. Los clientes que se conectan pocas veces se pierden esa ventana; los certificados de host evitan el problema.
  • Algoritmos. El mismo mecanismo sirve para una migración: añade una clave de host Ed25519 (y, más adelante, una híbrida), deja que los clientes la aprendan y después elimina la clave RSA.
  • Inventario. ssh-keygen -l -f authorized_keys imprime una huella digital por línea; compara esa salida con las líneas Accepted publickey … SHA256: del registro de sshd para encontrar claves que nadie usa.

Errores frecuentes

  • Un archivo de clave legible por todos. ssh se niega a usarlo y muestra WARNING: UNPROTECTED PRIVATE KEY FILE!. Aplica chmod 600 a la clave y 700 al directorio .ssh.
  • La frase de contraseña equivocada o una clave convertida. incorrect passphrase supplied to decrypt private key y error in libcrypto se parecen; el segundo suele significar que el archivo está dañado o en un formato que esa compilación no puede leer. Las bibliotecas necesitan la frase de contraseña de forma explícita, como muestra el error de Go this private key is passphrase protected.
  • Demasiadas claves en el agente. sshd se rinde tras MaxAuthTries (6) intentos fallidos y desconecta con Too many authentication failures, y cada clave que prueba el cliente puede gastar uno (los servidores OpenSSH 10.6 permiten 6 consultas adicionales del tipo «¿aceptarías esta clave?», PubkeyOptions max-pk-ok). Configura IdentityFile e IdentitiesOnly yes por host. Si no está registrada ninguna de las claves ofrecidas, obtienes Permission denied (publickey).
  • El agente se niega. agent refused operation significa que el servidor aceptó la clave, pero el agente no quiso firmar: una clave FIDO que no se tocó a tiempo, una confirmación que el agente no puede mostrar, un token bloqueado o un archivo de clave en el disco que ya no coincide con lo que guarda el agente.
  • Servidores antiguos. no matching host key type found. Their offer: ssh-rsa significa que el servidor solo puede firmar con SHA-1. Actualízalo; un HostKeyAlgorithms +ssh-rsa por host es una excepción temporal, nunca una configuración global.
  • Ignorar un cambio de clave de host. REMOTE HOST IDENTIFICATION HAS CHANGED es o bien una rotación planificada que puedes confirmar por otro canal, o bien justo el ataque para el que existe la comprobación. Elimina la línea antigua con ssh-keygen -R host solo cuando sepas cuál de las dos es.

Lista de comprobación

  1. ssh-keygen -t ed25519 (o -t ed25519-sk con una llave de seguridad), una frase de contraseña y un comentario con propietario, máquina y año.
  2. Sube las rondas de KDF hasta el retraso que aceptes (-a 100 cuesta aquí aproximadamente medio segundo).
  3. Una clave por dispositivo; nunca copies claves privadas entre máquinas.
  4. Agente con tiempos de vida; IdentitiesOnly yes por host; ProxyJump en lugar de ForwardAgent; ssh-add -h cuando el reenvío sea inevitable.
  5. Flotas: certificados de usuario y de host de validez corta, clave de la CA sin conexión y una KRL en cada servidor.
  6. Busca kex: algorithm: mlkem768x25519-sha256 en la salida de ssh -v; trata la advertencia poscuántica como una incidencia para actualizar el servidor.
  7. Prueba las claves mldsa44-ed25519 con tus propios servidores; mantén registrada una clave clásica hasta que todos los equipos remotos acepten la híbrida.

Fuentes