"Host key verification failed" en SSH, scripts y CI

SSH no pudo confirmar la identidad del servidor y se detuvo. Lo habitual es que el servidor aún no esté en known_hosts y nadie pueda responder la pregunta de sí o no, que es lo que pasa con BatchMode=yes, en cron y en CI. Añade la clave real del servidor a known_hosts del usuario que ejecuta el comando. Si además ves REMOTE HOST IDENTIFICATION HAS CHANGED, la clave es distinta de la guardada: averigua por qué antes de borrar la antigua.

Actualizada el . Reproducido con OpenSSH 10.3 en macOS contra un servidor OpenSSH 10.0 en Linux, con un archivo known_hosts temporal.

Qué ves

En un script con BatchMode=yes, o sin terminal donde preguntar, solo aparece una línea:

Host key verification failed.

Con StrictHostKeyChecking=yes hay un motivo encima:

No ED25519 host key is known for server and you have requested strict checking.
Host key verification failed.

Git añade sus propias líneas, que no significan que falte el repositorio:

Host key verification failed.
fatal: Could not read from remote repository.

Averigua en cuál de los casos estás

Ejecuta esto con el mismo usuario que ejecuta el comando que falla:

ssh-keygen -F server

Para un servidor en otro puerto, la entrada se guarda entre corchetes:

ssh-keygen -F '[server]:2222'
  • Sin salida: el host es desconocido para este usuario. Mira la causa 1 y la causa 2.
  • Se imprime una línea y el error muestra un gran aviso REMOTE HOST IDENTIFICATION HAS CHANGED: mira la causa 3.

Causa 1: el servidor no está en known_hosts

En una terminal, SSH te pediría confirmar la huella. BatchMode=yes prohíbe las preguntas, y un trabajo sin terminal no tiene a quién preguntar, así que SSH falla. Añade la clave de antemano.

Obtén la clave y compárala con la del servidor antes de confiar en ella:

ssh-keyscan -t ed25519 server > server.hostkey
ssh-keygen -lf server.hostkey

En el propio servidor, o desde una consola de tu proveedor:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

Si las dos huellas coinciden, instala la clave:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
cat server.hostkey >> ~/.ssh/known_hosts

Para un puerto distinto de 22, usa ssh-keyscan -p 2222 -t ed25519 server. ssh-keyscan por sí solo no demuestra nada, porque acepta lo que responda en esa dirección. La comparación es lo que lo hace seguro. Los servicios de alojamiento publican sus huellas, por ejemplo GitHub en la página de las fuentes.

En CI

Guarda la línea verificada como variable de CI y escríbela al principio del trabajo, en lugar de escanear en cada ejecución:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
printf '%s\n' "$KNOWN_HOSTS" >> ~/.ssh/known_hosts

accept-new y no

StrictHostKeyChecking=accept-new guarda una clave que no había visto nunca y sigue rechazando una que haya cambiado. Confía en la primera conexión sin comprobarla, algo aceptable para una máquina desechable en una red de confianza. Evita StrictHostKeyChecking=no: también deja continuar la conexión cuando la clave ha cambiado, que es justo la situación para la que existe esta comprobación.

Qué contiene cada línea del archivo: known_hosts explicado.

Causa 2: otro usuario u otro HOME

known_hosts pertenece a un usuario. Funciona en tu terminal y falla en el trabajo cuando este se ejecuta como otro: sudo ssh usa el archivo de root, y cron, las compilaciones de Docker y los runners de CI tienen su propia carpeta personal, a menudo vacía en cada ejecución.

whoami
echo "$HOME"
ssh -G server | grep -iE '^(userknownhostsfile|stricthostkeychecking) '

El último comando muestra qué archivos leerá SSH para ese host, sin conectar. Instala la clave para ese usuario, o indica al trabajo un archivo que controles:

ssh -o UserKnownHostsFile=/path/to/known_hosts -o BatchMode=yes user@server true

Causa 3: la clave guardada es distinta

La salida empieza entonces con ese aviso, y las dos últimas líneas son:

Host key for server has changed and you have requested strict checking.
Host key verification failed.

Lo más común es una reinstalación o un servidor nuevo en la misma dirección, pero así también se ve una interceptación. accept-new no lo salva. Compara las huellas como se ha explicado arriba y solo entonces borra la entrada antigua:

ssh-keygen -R server

Con github.com es habitual: GitHub sustituyó su clave de host RSA en marzo de 2023, así que una línea guardada antigua ahora falla. Bórrala con ssh-keygen -R github.com y añade las claves que publica GitHub, desde la página de las fuentes.

Más sobre este caso en REMOTE HOST IDENTIFICATION HAS CHANGED.

Preguntas

¿Qué significa Host key verification failed?

SSH no pudo confirmar la identidad del servidor y se detuvo. O el servidor no está en known_hosts y nadie podía responder a la pregunta, o su clave es distinta de la guardada.

¿Es StrictHostKeyChecking=no una solución segura en CI?

No. También acepta una clave cambiada. Instala la clave verificada en known_hosts, o usa accept-new en máquinas desechables dentro de una red de confianza.

¿Por qué funciona en mi terminal pero falla en cron?

known_hosts pertenece a un usuario. Cron, sudo y los runners de CI usan otro usuario u otra carpeta personal, donde falta la entrada guardada.

¿Por qué git dice Host key verification failed con GitHub?

O github.com no está en known_hosts para el usuario que ejecuta git, o sigue ahí una línea RSA guardada antes de marzo de 2023. Bórrala con ssh-keygen -R github.com y añade las claves de la página de huellas de GitHub.

Fuentes

Más en Mensajes de error

Todas las guías