Ana ya tiene su remoto registrado. Escribe git push origin main con toda la ilusión y obtiene esto:
Un prompt esperando algo que no sabe muy bien qué es. Y si teclea la contraseña con la que entra en la interfaz web, es muy probable que reciba un rechazo del tipo Support for password authentication was removed.
Este muro detiene a mucha gente en su primer contacto con un repositorio remoto, y es una lástima, porque el problema no tiene nada que ver con Git: es un problema de identidad. Registrar una URL no da permiso para escribir en ella. Alguien tiene que demostrarle al servidor que es quien dice ser.
Esta lección resuelve ese muro de una vez y para siempre. Veremos por qué el clone de un repositorio público no pide nada y el push sí, los dos mecanismos de autenticación que se usan hoy —tokens sobre HTTPS y claves SSH—, cómo generar una clave con ssh-keygen, y cómo hacer que el sistema operativo recuerde las credenciales para no teclearlas cuarenta veces al día. Es la lección que Carla necesita antes de escribir su primera línea, porque entra desde Windows 11 y ahí el gestor de credenciales funciona de forma distinta.
Contenido
- Por qué el
clonepúblico no pide nada y elpushsí - Autenticación frente a autorización
- HTTPS con token personal de acceso
- SSH: el par de claves
- Generar la clave con
ssh-keygen -t ed25519 - Subir la pública, probar la conexión y usar el agente
~/.ssh/config: varias identidades en la misma máquina- HTTPS frente a SSH: tabla comparativa
- Gestores de credenciales por sistema operativo
- Errores típicos y cómo diagnosticarlos
- Por qué el
clone público no pide nada y el push sí
clone público no pide nada y el push síLa respuesta es sencilla y despeja mucha confusión: son operaciones con requisitos de permiso distintos.
| Operación | Qué hace | Repositorio público | Repositorio privado |
|---|---|---|---|
git clone, git fetch, git pull |
Leer objetos y referencias | Sin credenciales | Credenciales |
git push |
Escribir: modificar referencias del servidor | Credenciales siempre | Credenciales |
Un repositorio público es, por definición, legible por cualquiera. Descargar el código de un proyecto abierto no requiere identificarse, igual que leer una página web no requiere cuenta.
Escribir es otra historia. Cuando envías, le estás pidiendo al servidor que modifique sus referencias: que refs/heads/main pase a apuntar a otro commit. Eso cambia lo que todo el mundo verá al clonar a partir de ese momento. Ningún servidor sensato permite eso a un desconocido.
Y hay un matiz que sorprende a mucha gente: la identidad de Git y la identidad del servidor son cosas distintas.
Ana Ferrer [email protected]
Eso que configuraste en la lección 01-06 es metadato del commit: texto que se graba dentro del objeto y que aparece en git log. No autentica nada. Cualquiera puede poner cualquier nombre y cualquier correo en sus commits; Git no lo verifica.
La autenticación ocurre en otra capa: en el transporte, cuando tu Git habla con el servidor. Son dos identidades independientes que conviene no mezclar:
user.name / user.email |
Credenciales de acceso | |
|---|---|---|
| Dónde vive | En la configuración de Git | En el gestor de credenciales o en ~/.ssh/ |
| Para qué sirve | Firmar la autoría del commit | Demostrar quién eres ante el servidor |
| Lo verifica alguien | No | Sí, el servidor, en cada conexión |
| Cuándo interviene | Al hacer git commit |
Al hacer fetch, pull o push |
(Existe una forma de vincular ambas cosas de verdad, firmando los commits criptográficamente. Es un tema de seguridad y se trata en la lección 08-05.)
- Autenticación frente a autorización
Dos palabras que se confunden a diario y que producen errores muy distintos:
- Autenticación: quién eres. Demostrar tu identidad ante el servidor.
- Autorización: qué puedes hacer. Los permisos que esa identidad tiene sobre ese repositorio concreto.
Puedes estar perfectamente autenticado y aun así recibir un rechazo:
remote: Permission to equipo/gestor-tareas.git denied to carla. fatal: unable to access 'https://git.ejemplo.es/equipo/gestor-tareas.git/': The requested URL returned error: 403
Fíjate en el mensaje: el servidor sabe que eres Carla. La autenticación ha funcionado. Lo que falla es la autorización: a Carla no le han dado permiso de escritura en ese repositorio, o su token no tiene el ámbito necesario.
Distinguir los dos casos ahorra mucho tiempo:
| Síntoma | Capa que falla | Qué revisar |
|---|---|---|
Permission denied (publickey) |
Autenticación (SSH) | La clave: si existe, si está cargada, si está subida al servidor |
Authentication failed (HTTPS) |
Autenticación | El token: si es válido, si ha caducado, si está bien guardado |
403 Forbidden, Permission to … denied to <usuario> |
Autorización | Los permisos de tu cuenta en el repositorio; los ámbitos del token |
Repository not found |
Ambas, ambiguamente | Muchas plataformas devuelven esto para repositorios privados a los que no tienes acceso, para no revelar que existen |
Ese último caso es especialmente traicionero: Repository not found no significa necesariamente que hayas escrito mal la URL. Puede significar "existe, pero para ti no".
- HTTPS con token personal de acceso
Qué es un PAT y por qué sustituyó a la contraseña
Un token personal de acceso (Personal Access Token, PAT) es una cadena larga generada por la plataforma que funciona como contraseña para un uso concreto. Tiene un aspecto parecido a este (ficticio, evidentemente):
Durante años, la autenticación por HTTPS se hacía con el usuario y la contraseña de la cuenta. GitHub retiró esa posibilidad en agosto de 2021 y el resto de plataformas siguió el mismo camino. Las razones son sólidas:
- Ámbito limitado. Tu contraseña abre toda la cuenta: repositorios, ajustes, facturación, borrado. Un token puede dar solo lectura de un repositorio concreto.
- Revocable individualmente. Si un token se filtra, lo eliminas y solo se rompe lo que lo usaba. Cambiar la contraseña te obliga a reconfigurar todo.
- Compatible con doble factor. Si tu cuenta tiene segundo factor, no hay forma de introducirlo en un prompt de Git. El token resuelve ese callejón sin salida.
- Caducidad. Un token puede expirar en 30, 60 o 90 días; una contraseña vive hasta que alguien se acuerda de cambiarla.
- Auditable. La plataforma registra qué token hizo qué y cuándo se usó por última vez.
Cómo se crea y con qué ámbitos
El procedimiento concreto varía por plataforma, pero el esquema es siempre el mismo: ajustes de la cuenta → tokens de acceso → crear → elegir nombre, caducidad y ámbitos.
Los ámbitos son la parte importante. Concede el mínimo imprescindible:
| Necesidad | Ámbito típico | Qué permite |
|---|---|---|
Clonar y hacer fetch de repositorios privados |
read_repository / repo:read |
Solo lectura |
Hacer push |
write_repository / repo |
Lectura y escritura de código |
| Solo un repositorio concreto | Token con ámbito de proyecto | Acceso acotado a ese repositorio |
| Integración continua | El mínimo que necesite la tarea | Ver módulo 7 |
Lo que casi nunca necesitas: ámbitos de administración, de gestión de usuarios, de borrado de repositorios o de acceso a los ajustes de la organización. Un token de despliegue que solo tiene que clonar no debería poder borrar nada.
Un consejo operativo: crea un token por máquina, no uno que compartas entre tu portátil, tu ordenador de casa y el servidor de integración continua. Si pierdes el portátil, revocas ese token y el resto sigue funcionando.
Cómo se usa
El token se introduce en el sitio de la contraseña:
Username for 'https://git.ejemplo.es': ana.ferrer Password for 'https://[email protected]':
En ese segundo prompt va el token, no la contraseña de la cuenta. Como no se ve mientras se escribe, es cómodo pegarlo desde el portapapeles.
Lo que no debes hacer nunca es incrustarlo en la URL:
# MAL: no hagas esto
git remote add origin https://ana:[email protected]/equipo/gestor-tareas.gitEse token acaba escrito en texto plano en .git/config, aparece en el historial de tu shell, se cuela en capturas de pantalla y sale en cualquier git remote -v que ejecutes delante de alguien. Para eso existen los gestores de credenciales del apartado 9.
- SSH: el par de claves
La alternativa a HTTPS es SSH, y se basa en un concepto distinto: en lugar de un secreto compartido, se usa un par de claves asimétricas.
- La clave privada (
~/.ssh/id_ed25519) se queda en tu máquina y no sale de ahí jamás. Es el equivalente a tu llave física. - La clave pública (
~/.ssh/id_ed25519.pub) se sube al servidor. Es el equivalente a la cerradura: se puede repartir sin riesgo.
La propiedad matemática que lo hace funcionar es que lo que se verifica con la pública solo lo ha podido producir la privada, y la privada no se puede deducir de la pública.
sequenceDiagram
participant C as Portátil de Carla
participant S as git.ejemplo.es
C->>S: Quiero conectarme como usuario "git"
S->>C: Reto: firma este dato aleatorio
Note over C: Firma con la clave PRIVADA<br/>(que nunca sale del disco)
C->>S: Aquí tienes la firma
Note over S: Verifica con la clave PÚBLICA<br/>que Carla subió antes
S->>C: Verificada. Acceso concedido
La ventaja sobre el token es evidente: el secreto nunca viaja por la red. Ni siquiera cifrado. Lo único que se transmite es una firma de un dato aleatorio distinto en cada conexión, inútil para un atacante que la capture.
Los tipos de clave
| Tipo | Estado | Comentario |
|---|---|---|
| Ed25519 | Recomendado | Moderno, rápido, claves cortas (68 caracteres), seguridad excelente |
| RSA 4096 | Aceptable | Seguro, pero claves largas y más lento; útil en sistemas antiguos que no admiten Ed25519 |
| RSA 2048 | Desaconsejado | Ya no se considera suficiente |
| ECDSA | Desaconsejado | Dudas sobre las curvas estándar; Ed25519 lo supera en todo |
| DSA | Prohibido | Obsoleto y eliminado de OpenSSH |
Usa Ed25519 salvo que te encuentres con un servidor antiguo que lo rechace, en cuyo caso rsa con 4096 bits.
- Generar la clave con
ssh-keygen -t ed25519
ssh-keygen -t ed25519Carla, desde su Windows 11, abre Git Bash (que instaló en la lección 01-02 y que trae todas las herramientas de OpenSSH). Los comandos son idénticos en Linux, macOS y Git Bash:
ssh-keygen -t ed25519 -C "[email protected]"Desglose de las opciones:
-t ed25519: el tipo de clave. Es el argumento importante.-C "…": un comentario que se añade al final de la clave pública. Sirve para identificarla en la lista del servidor cuando tengas cuatro claves de cuatro máquinas. Puede ser el correo, pero es incluso mejor algo como"carla-portatil-windows", porque lo que quieres saber es de qué máquina es esa clave.
El diálogo:
Generating public/private ed25519 key pair. Enter file in which to save the key (/c/Users/carla/.ssh/id_ed25519):
Pulsa Intro para aceptar la ruta por defecto. Solo cámbiala si vas a tener varias claves, caso que veremos en el apartado 7.
Aquí hay que detenerse. La passphrase cifra la clave privada en el disco. Si alguien te roba el portátil o copia el fichero, sin ella la clave es inservible.
| Con passphrase | Sin passphrase | |
|---|---|---|
| Seguridad si te roban el fichero | La clave es inútil sin la frase | Acceso inmediato a tus repositorios |
| Comodidad diaria | Se teclea una vez por sesión (con ssh-agent) |
Nunca se teclea |
| Uso en automatización sin supervisión | Complicado | Es lo habitual, con la clave muy restringida |
| Recomendación | Ponla siempre en máquinas personales | Solo en claves de despliegue de solo lectura |
Ponla. Con ssh-agent, el coste real es teclearla una vez al arrancar el ordenador.
El resultado:
Your identification has been saved in /c/Users/carla/.ssh/id_ed25519 Your public key has been saved in /c/Users/carla/.ssh/id_ed25519.pub The key fingerprint is: SHA256:9xK2mQ7RtVb3Ln8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected]
Dos ficheros. Veamos qué contienen:
-rw------- 1 carla carla 464 ago 1 09:12 id_ed25519 -rw-r--r-- 1 carla carla 103 ago 1 09:12 id_ed25519.pub
Fíjate en los permisos, que son parte del mecanismo de seguridad:
- La privada es
-rw-------(600): solo tú puedes leerla. Si tuviera permisos más abiertos, OpenSSH se negaría a usarla. - La pública es
-rw-r--r--(644): legible por cualquiera, y no pasa nada.
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK7Rt2mQx9VbLn8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected]
Tres partes: el tipo, la clave en sí y el comentario. Esta línea es la que se sube al servidor, y se puede publicar sin ningún riesgo.
Y la privada, con la advertencia obvia:
-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDl...
Este contenido no se enseña, no se copia y no se envía a nadie. Nunca. Ni a un compañero, ni a soporte técnico, ni pegado en un chat. Si alguna vez tienes la duda de cuál de los dos ficheros hay que subir, la regla es infalible: el que acaba en .pub.
- Subir la pública, probar la conexión y usar el agente
Subir la clave pública
Se copia el contenido del .pub y se pega en la plataforma (ajustes de la cuenta → claves SSH → nueva clave). Para copiarlo al portapapeles:
# Linux (con xclip instalado)
xclip -selection clipboard < ~/.ssh/id_ed25519.pub
# macOS
pbcopy < ~/.ssh/id_ed25519.pub
# Windows con Git Bash
clip < ~/.ssh/id_ed25519.pubUn aviso frecuente: al pegar, no debe quedar ningún salto de línea en medio. La clave es una sola línea larga; si el editor la parte, no funcionará.
Probar la conexión con ssh -T
Antes de intentar ningún comando de Git, comprueba que el canal funciona:
ssh -T [email protected]La opción -T significa "no quiero terminal interactiva": solo estoy comprobando la autenticación.
La primera vez aparece esto:
The authenticity of host 'git.ejemplo.es (192.0.2.42)' can't be established. ED25519 key fingerprint is SHA256:p2Q9xL4mR7tVc3Nb8ZwYeF6dJ1sK5uA0eB7gN2kM9o. Are you sure you want to continue connecting (yes/no/[fingerprint])?
No respondas yes por inercia. Ese mensaje dice que tu ordenador no conoce todavía a ese servidor y te pide que confirmes que es el auténtico. Las plataformas publican sus huellas en su documentación; compárala antes de aceptar. Es la única defensa contra un ataque de intermediario en esa primera conexión.
Al aceptar, la huella se guarda en ~/.ssh/known_hosts y no volverá a preguntar.
Si todo va bien:
Ese mensaje es un éxito completo, aunque diga que no da acceso al shell. Eso es exactamente lo que debe pasar: el usuario git de un servidor de repositorios no sirve para abrir una sesión, solo para hablar Git.
ssh-agent: teclear la passphrase una sola vez
Con passphrase, cada operación pediría la frase. El agente la guarda en memoria durante la sesión y responde por ti.
Enter passphrase for /home/carla/.ssh/id_ed25519: Identity added: /home/carla/.ssh/id_ed25519 ([email protected])
256 SHA256:9xK2mQ7RtVb3Ln8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected] (ED25519)
A partir de aquí, todos los push y pull funcionan sin teclear nada.
Cada sistema tiene su forma de dejarlo automatizado:
# Linux: añadir al final de ~/.bashrc o ~/.zshrc
if [ -z "$SSH_AUTH_SOCK" ]; then
eval "$(ssh-agent -s)" > /dev/null
ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi# macOS: guarda la passphrase en el Llavero y la carga sola
ssh-add --apple-use-keychain ~/.ssh/id_ed25519# macOS: y para que se cargue en cada sesión, en ~/.ssh/config
Host *
UseKeychain yes
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519En Windows 11, el servicio ssh-agent viene con el sistema pero arranca desactivado. Desde PowerShell como administrador:
Y después, ya desde Git Bash:
Un detalle para Carla: si usa el ssh de Git Bash y el agente del sistema, pueden no verse entre sí. La solución sencilla es usar el bloque de ~/.bashrc de arriba, que arranca un agente propio de Git Bash.
~/.ssh/config: varias identidades en la misma máquina
~/.ssh/config: varias identidades en la misma máquinaSituación muy real, y precisamente la de Carla: en la lección 01-05 vimos que trabaja en dos contextos, el de ejemplo.es y el de otra empresa, con correos distintos. Si además cada uno exige una cuenta y una clave distintas, hace falta decirle a SSH cuál usar en cada caso.
Eso se resuelve en ~/.ssh/config:
# Cuenta del trabajo
Host git.ejemplo.es
HostName git.ejemplo.es
User git
IdentityFile ~/.ssh/id_ed25519_trabajo
IdentitiesOnly yes
AddKeysToAgent yes
# Cuenta de la otra empresa: alias inventado
Host git-otraempresa
HostName git.otraempresa.es
User git
IdentityFile ~/.ssh/id_ed25519_otraempresa
IdentitiesOnly yes
AddKeysToAgent yesExplicación de cada directiva:
| Directiva | Qué hace |
|---|---|
Host |
El alias que escribes en la URL. Puede ser inventado |
HostName |
El servidor real al que conectarse |
User |
El usuario SSH: en las plataformas de Git es casi siempre git |
IdentityFile |
Qué clave privada usar para este destino |
IdentitiesOnly yes |
Usa solo esa clave, no todas las que tengas cargadas |
AddKeysToAgent yes |
Carga la clave en el agente al primer uso |
IdentitiesOnly yes merece un comentario, porque evita un fallo desconcertante. Sin él, SSH ofrece todas tus claves una tras otra hasta que alguna funcione; si tienes cinco, el servidor puede cortar la conexión por exceso de intentos y obtendrás un Too many authentication failures que no parece tener nada que ver con la causa real.
El truco del alias inventado es lo que hace potente este fichero. Fíjate en Host git-otraempresa: ese nombre no existe en ningún DNS. Pero ahora Carla puede escribir:
Y SSH traduce git-otraempresa a git.otraempresa.es con la clave correcta. El mismo mecanismo sirve para dos cuentas en la misma plataforma, que es el caso clásico de tener una cuenta personal y otra de empresa en el mismo GitHub:
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
Host github-empresa
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_empresa
IdentitiesOnly yes# Repositorio personal
git clone git@github-personal:carla/mi-blog.git
# Repositorio de la empresa
git clone git@github-empresa:ejemplo-sl/gestor-tareas.gitMismo servidor real, dos identidades, sin ninguna ambigüedad.
Y para comprobar qué clave se va a usar realmente:
ssh -T -v [email protected] 2>&1 | grep -i "offering\|identity file"debug1: identity file /home/carla/.ssh/id_ed25519_trabajo type 3 debug1: Offering public key: /home/carla/.ssh/id_ed25519_trabajo ED25519
La opción -v (verbose) es la herramienta de diagnóstico definitiva para cualquier problema de SSH.
Permisos del fichero, que también son estrictos:
- HTTPS frente a SSH: tabla comparativa
Las dos opciones son válidas y las dos se usan masivamente. La elección depende del contexto:
| Criterio | HTTPS + token | SSH |
|---|---|---|
| Facilidad inicial | Alta: pegar un token y listo | Media: generar clave, subirla, probar |
| Cortafuegos corporativos | Excelente: usa el puerto 443, abierto en todas partes | Problemática: el puerto 22 suele estar cerrado |
| Uso diario | Transparente con gestor de credenciales | Transparente con ssh-agent |
| El secreto viaja por la red | Sí (dentro del cifrado TLS) | No, nunca |
| Caducidad | Sí: hay que renovar el token cada 30-90 días | No caduca |
| Granularidad de permisos | Alta: ámbitos por token | Baja: la clave da lo que da tu cuenta |
| Varias identidades | Complicado: el gestor guarda una por servidor | Sencillo con ~/.ssh/config |
| Automatización y CI | Preferido: tokens con ámbito mínimo y caducidad | Posible con claves de despliegue |
| Revocación | Inmediata desde la web | Inmediata borrando la clave |
| Repositorios públicos de solo lectura | Ideal: sin credenciales | Innecesario |
| Detrás de un proxy | Se configura fácilmente en Git | Requiere configuración adicional de SSH |
Recomendación práctica
- Máquina de trabajo diaria, misma cuenta siempre → SSH. Se configura una vez y se olvida: no caduca, no se renueva y no interrumpe.
- Red corporativa con el puerto 22 cerrado → HTTPS + token. (Algunas plataformas ofrecen SSH por el puerto 443 como alternativa.)
- Integración continua, contenedores, servidores → Token con el ámbito mínimo y caducidad corta, o una clave de despliegue de solo lectura.
- Clonar un proyecto público para leerlo → HTTPS sin credenciales.
- Varias cuentas en la misma máquina → SSH con
~/.ssh/config.
Y un dato tranquilizador: cambiar de una a otra es un set-url, como vimos en la lección anterior:
# De HTTPS a SSH
git remote set-url origin [email protected]:equipo/gestor-tareas.git
# De SSH a HTTPS
git remote set-url origin https://git.ejemplo.es/equipo/gestor-tareas.gitNo pierdes nada: los commits son los mismos, las referencias son las mismas y solo cambia el camino.
- Gestores de credenciales por sistema operativo
Con HTTPS queda un problema práctico: nadie va a teclear un token de 40 caracteres en cada push. Para eso existe credential.helper, que ya asomó en la lección 01-06 y que ahora podemos entender del todo.
Un credential helper es un programa externo al que Git le pregunta "¿tienes credenciales para este servidor?" antes de mostrar el prompt, y al que le dice "guárdate estas" cuando el acceso funciona.
sequenceDiagram
participant G as git push
participant H as credential.helper
participant A as Almacén del sistema
participant S as Servidor
G->>H: ¿Credenciales para git.ejemplo.es?
H->>A: Consulta (cifrada)
A-->>H: usuario + token
H-->>G: Aquí están
G->>S: Autenticación
S-->>G: Correcto
Note over G,A: Si fallan, Git pregunta al usuario<br/>y pide al helper que guarde las nuevas
El de cada sistema
Linux (Ana, Ubuntu) — libsecret
Se integra con el llavero del escritorio (GNOME Keyring, KWallet), que guarda los secretos cifrados y se desbloquea con la sesión:
sudo apt install libsecret-1-0 libsecret-1-dev
# Compilar el ayudante que viene con Git
sudo make --directory=/usr/share/doc/git/contrib/credential/libsecret
git config --global credential.helper \
/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecretEn algunas distribuciones viene ya compilado y basta con instalar el paquete correspondiente.
macOS (Bruno) — osxkeychain
Viene incluido con Git en macOS; una sola línea:
Las credenciales se guardan en el Llavero, cifradas y visibles en la aplicación Acceso a Llaveros, donde se pueden revisar y borrar.
Windows 11 (Carla) — Git Credential Manager
Es el caso más interesante, y por eso lo dejamos para el final. GCM se instala junto con Git para Windows y queda configurado por defecto:
Lo que hace GCM va más allá de guardar una cadena:
- Guarda las credenciales en el Administrador de credenciales de Windows, cifradas con la cuenta de usuario del sistema.
- Abre una ventana de navegador para autenticarse contra GitHub, GitLab o Azure DevOps, con soporte para doble factor.
- Puede generar y renovar tokens por sí mismo, de modo que Carla no tiene que crear ninguno a mano.
- Es multiplataforma: existe también para Linux y macOS, aunque en esos sistemas los nativos suelen bastar.
Para Carla, esto significa que su primer git clone de un repositorio privado abrirá una ventana del navegador, ella entrará con su cuenta y su segundo factor, y a partir de ahí no volverá a ver un prompt. Es, con diferencia, la experiencia más cómoda de las tres.
Si quiere comprobar qué hay guardado, puede abrirlo desde Git Bash:
Las entradas de Git aparecen en la sección "Credenciales genéricas" con el prefijo git:.
Resumen y store, el que no debes usar
| Ayudante | Sistema | Dónde guarda | Cifrado | Recomendación |
|---|---|---|---|---|
manager |
Windows (y multiplataforma) | Administrador de credenciales de Windows | Sí | La opción en Windows |
osxkeychain |
macOS | Llavero del sistema | Sí | La opción en macOS |
libsecret |
Linux | Llavero del escritorio | Sí | La opción en Linux |
cache |
Cualquiera | Memoria RAM, temporalmente | No aplica: no toca el disco | Aceptable: seguro pero olvidadizo |
store |
Cualquiera | ~/.git-credentials, texto plano |
NO | Evítalo |
Por qué store guarda en texto plano y cuándo (no) usarlo
Es tentador por lo fácil que es:
Y funciona a la primera. El problema se ve al mirar el fichero que crea:
https://ana.ferrer:[email protected]
Tu token, legible, en un fichero de tu carpeta personal. Sin cifrar, sin contraseña maestra, sin caducidad. Los permisos son 600, lo cual protege de otros usuarios de la misma máquina, pero no de:
- Cualquier programa que se ejecute con tu usuario, incluida una dependencia maliciosa de tu proyecto.
- Una copia de seguridad de tu carpeta personal que acabe en un disco externo o en la nube.
- Alguien que arranque el ordenador desde un USB o extraiga el disco.
- Un fichero de configuración sincronizado por error entre máquinas.
Cuándo no usarlo: en tu portátil, en tu ordenador de sobremesa, en cualquier máquina con acceso a repositorios que importen.
Cuándo podría tener sentido: en un contenedor efímero o una máquina virtual desechable, aislada, con un token de solo lectura y caducidad de horas, donde no hay ningún llavero disponible y el ciclo de vida de la máquina es más corto que el del token. Incluso ahí, casi siempre hay una opción mejor.
La alternativa razonable cuando no hay llavero es cache, que mantiene las credenciales en memoria durante un tiempo limitado:
Una hora sin volver a teclear, y nada tocando el disco. Al apagar, desaparece.
Todo lo relativo a la gestión de secretos, la firma de commits y el tratamiento de credenciales filtradas en el historial se desarrolla en la lección 08-05. Aquí nos hemos ocupado de lo operativo: poder trabajar de forma cómoda sin dejar secretos tirados.
- Errores típicos y cómo diagnosticarlos
Permission denied (publickey)
[email protected]: Permission denied (publickey). fatal: Could not read from remote repository.
Es el error de SSH más habitual. Significa: "El servidor no ha aceptado ninguna de las claves que le has ofrecido." Las causas, en orden de frecuencia:
Si responde Could not open a connection to your authentication agent, el agente no está en marcha:
Si responde The agent has no identities, está en marcha pero vacío: falta el ssh-add.
# 3. ¿La clave pública subida al servidor es la misma que tienes?
ssh-keygen -lf ~/.ssh/id_ed25519.pub256 SHA256:9xK2mQ7RtVb3Ln8ZwYcF4dJ6hP1sT5uA2eB9gN0kM3o [email protected] (ED25519)
Compara esa huella con la que muestra la plataforma en la lista de claves. Si no coincide, subiste otra.
# 4. ¿Los permisos son correctos?
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pubOpenSSH ignora en silencio las claves privadas con permisos demasiado abiertos, lo cual produce este error sin ninguna pista.
# 5. El diagnóstico definitivo
ssh -vT [email protected]En la salida verás qué claves ofrece (Offering public key:) y cómo responde el servidor. Es la forma más rápida de descubrir que estás ofreciendo la clave equivocada.
Host key verification failed
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Significa que la clave del servidor no coincide con la que tenías guardada en ~/.ssh/known_hosts. Hay dos explicaciones posibles:
- Legítima: el servidor se ha reinstalado, se ha migrado o la plataforma ha rotado sus claves (ocurre de vez en cuando y siempre se anuncia públicamente).
- Ataque de intermediario: alguien se está haciendo pasar por el servidor.
No borres la entrada sin comprobar. El procedimiento correcto:
# 1. Ver qué huella está presentando el servidor ahora
ssh-keyscan git.ejemplo.es 2>/dev/null | ssh-keygen -lf -# 2. Comparar con la huella oficial publicada por la plataforma.
# Si y solo si coincide, eliminar la entrada antigua:
ssh-keygen -R git.ejemplo.es
# 3. Reconectar y aceptar la nueva
ssh -T [email protected]La variante suave del mismo aviso —The authenticity of host … can't be established— es la primera conexión: no hay nada guardado todavía. También ahí conviene comparar la huella antes de aceptar.
Otros errores frecuentes
| Mensaje | Causa habitual | Solución |
|---|---|---|
Support for password authentication was removed |
Estás usando la contraseña de la cuenta | Genera un token y úsalo en su lugar |
Authentication failed for 'https://…' |
Token caducado, revocado o mal guardado | Borra la credencial del gestor y vuelve a autenticarte |
403 Forbidden / Permission to … denied |
Autorización, no autenticación | Revisa permisos en el repositorio y ámbitos del token |
Repository not found |
Repositorio privado sin acceso, o URL errónea | Verifica la URL y tus permisos |
Connection timed out (puerto 22) |
Cortafuegos bloqueando SSH | Usa HTTPS, o SSH por el puerto 443 si la plataforma lo ofrece |
Too many authentication failures |
SSH ofrece demasiadas claves | IdentitiesOnly yes en ~/.ssh/config |
Load key … bad permissions |
Permisos demasiado abiertos en la privada | chmod 600 ~/.ssh/id_ed25519 |
Y un comando que resuelve el "no sé qué credencial está usando Git":
Muestra el proceso completo, incluido qué ayudante de credenciales se invoca. Úsalo solo para depurar y no compartas su salida sin revisarla, porque puede incluir cabeceras sensibles.
Errores Comunes y Consejos
Error 1: subir la clave privada en lugar de la pública. Ocurre más de lo que parece. La regla es simple: se sube el fichero que termina en .pub. Si has subido la privada por error, bórrala del servidor, elimina el par entero de tu disco y genera uno nuevo: esa clave está comprometida para siempre.
Error 2: incrustar el token en la URL del remoto. Acaba en .git/config, en el historial de la shell y en cualquier captura de pantalla. Usa un gestor de credenciales.
Error 3: crear la clave sin passphrase "para ir rápido". El robo del portátil pasa de ser un problema de hardware a ser un problema de acceso a todos tus repositorios. Con ssh-agent, la passphrase se teclea una vez por sesión.
Error 4: confundir user.email con la identidad de acceso. Cambiar user.email no arregla ningún problema de autenticación: solo cambia el texto que aparece en los commits. Son capas distintas.
Error 5: aceptar la huella del servidor sin mirarla. Ese prompt de la primera conexión es la única oportunidad de detectar una suplantación. Las plataformas publican sus huellas; compararlas cuesta diez segundos.
Error 6: usar el mismo token en cinco máquinas. Cuando haya que revocarlo, se romperán las cinco a la vez y no sabrás cuál se filtró. Un token por máquina y por propósito.
Error 7: usar credential.helper store por defecto. Deja el token en texto plano en tu carpeta personal. Usa el gestor nativo de tu sistema, o cache si no hay ninguno disponible.
Consejo 1: prueba siempre con ssh -T antes de culpar a Git. Si ssh -T git@servidor funciona, el problema no está en SSH. Si no funciona, ssh -vT te dice exactamente en qué paso falla.
Consejo 2: pon un comentario útil en la clave. -C "carla-portatil-windows" es infinitamente más práctico que el correo cuando dentro de un año veas cuatro claves en la lista del servidor y tengas que decidir cuál revocar.
Consejo 3: apunta la caducidad de tus tokens. Un token que expira un lunes por la mañana genera media hora de desconcierto. Ponte un recordatorio unos días antes.
Consejo 4: IdentitiesOnly yes siempre que tengas más de una clave. Evita el Too many authentication failures, que es de los errores más difíciles de relacionar con su causa.
Consejo 5: para automatización, ámbito mínimo y caducidad corta. Un token de integración continua que solo tiene que clonar no necesita permiso de escritura ni de administración.
Ejercicios
Ejercicio 1: generar y auditar un par de claves
Sin subir nada a ningún servidor:
- Genera un par Ed25519 en una ruta específica:
~/.ssh/practica_curso, con un comentario descriptivo. - Muestra los permisos de los dos ficheros y explica por qué son distintos.
- Muestra la huella de la clave pública.
- Cárgala en
ssh-agenty verifica que aparece listada. - Comprueba que la huella de la clave privada y la de la pública coinciden. Explica por qué.
- Descárgala del agente y elimina los ficheros.
Ejercicio 2: configurar dos identidades
Carla necesita trabajar con dos cuentas: la del equipo (git.ejemplo.es) y la de otra empresa (git.otraempresa.es).
- Escribe el
~/.ssh/configcompleto para las dos, con claves separadas. - Explica qué hace cada directiva.
- Escribe la URL de clonado que usaría para cada repositorio.
- Indica el comando que le permitiría comprobar qué clave concreta se ofrece a cada servidor.
- Explica qué pasaría si omitiera
IdentitiesOnly yesy tuviera seis claves cargadas.
Ejercicio 3: diagnóstico
Para cada uno de estos mensajes, indica: (a) si el fallo es de autenticación o de autorización, (b) las dos causas más probables y (c) el comando o comprobación con el que empezarías.
[email protected]: Permission denied (publickey).remote: Permission to equipo/gestor-tareas.git denied to carla.remote: Support for password authentication was removed.WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!ssh: connect to host git.ejemplo.es port 22: Connection timed out
Soluciones
Solución 1:
# 1. Generar con ruta y comentario
ssh-keygen -t ed25519 -f ~/.ssh/practica_curso -C "practica-curso-git"Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/carla/.ssh/practica_curso Your public key has been saved in /home/carla/.ssh/practica_curso.pub The key fingerprint is: SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curso-git
La opción -f fija la ruta y evita el diálogo de "dónde guardar".
-rw------- 1 carla carla 464 ago 1 10:22 /home/carla/.ssh/practica_curso -rw-r--r-- 1 carla carla 103 ago 1 10:22 /home/carla/.ssh/practica_curso.pub
La privada es 600: solo su dueño puede leerla, y OpenSSH se niega a usarla si tuviera permisos más laxos, porque cualquier otro usuario del sistema podría copiarla. La pública es 644 porque está diseñada para repartirse: no revela nada explotable.
Agent pid 6120 Enter passphrase for /home/carla/.ssh/practica_curso: Identity added: /home/carla/.ssh/practica_curso (practica-curso-git) 256 SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curso-git (ED25519)
256 SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curso-git (ED25519) 256 SHA256:4tR8mK2nQ7xVb3Lc9ZwYeF6dJ1sP5uA0eB7gN2kM3o practica-curso-git (ED25519)
Idénticas, y no es casualidad. La huella es un hash de la clave pública, y la pública se puede derivar de la privada (lo contrario no). Cuando ssh-keygen -lf recibe una clave privada, extrae la pública y calcula su huella. Por eso la huella sirve para emparejar sin ambigüedad qué privada de tu disco corresponde a qué pública subida al servidor: es exactamente la comprobación del apartado 10.
Solución 2:
# Primero, las dos claves
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_trabajo -C "carla-trabajo-ejemplo"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_otraempresa -C "carla-otraempresa"1. El fichero ~/.ssh/config:
# Identidad del equipo de gestor-tareas
Host git.ejemplo.es
HostName git.ejemplo.es
User git
IdentityFile ~/.ssh/id_ed25519_trabajo
IdentitiesOnly yes
AddKeysToAgent yes
# Identidad de la otra empresa (alias inventado)
Host git-otraempresa
HostName git.otraempresa.es
User git
IdentityFile ~/.ssh/id_ed25519_otraempresa
IdentitiesOnly yes
AddKeysToAgent yes2. Qué hace cada directiva:
Host: el nombre que Carla escribe en la URL. En el primer bloque coincide con el servidor real; en el segundo es un alias inventado que no existe en ningún DNS.HostName: el servidor real al que hay que conectarse. Es lo que resuelve el alias.User git: el usuario SSH. En las plataformas de repositorios es siempregit; el usuario real se deduce de la clave que presentas.IdentityFile: qué clave privada usar con este destino.IdentitiesOnly yes: usar solo esa clave, sin ofrecer las demás.AddKeysToAgent yes: cargarla en el agente al primer uso, para no repetir la passphrase.
3. Las URL de clonado:
# Repositorio del equipo
git clone [email protected]:equipo/gestor-tareas.git
# Repositorio de la otra empresa: se usa el ALIAS
git clone git@git-otraempresa:proyectos/facturacion.git4. Comprobar qué clave se ofrece:
ssh -T -v [email protected] 2>&1 | grep "Offering public key"Cada destino recibe exactamente una clave, la suya.
5. Sin IdentitiesOnly yes: SSH ofrecería todas las claves cargadas en el agente, una por una, en un orden que no controlas. Con seis claves y un servidor cuyo MaxAuthTries está en 6 (el valor habitual), es muy probable que agote los intentos antes de llegar a la correcta:
Un error especialmente traicionero, porque la clave correcta existe y está cargada: simplemente no le ha dado tiempo a probarla. Además, ofrecer todas tus claves a cualquier servidor con el que hables es una fuga de información innecesaria: le revelas cuántas identidades tienes.
Solución 3:
1. Permission denied (publickey)
- (a) Autenticación. El servidor no ha aceptado ninguna clave: ni siquiera sabe quién eres.
- (b) La clave no está cargada en el agente, o la que tienes en el disco no es la que está subida al servidor. Menos frecuente pero muy desconcertante: permisos demasiado abiertos en la privada, que hacen que OpenSSH la ignore en silencio.
- (c)
ssh-add -lpara ver qué hay cargado y, si eso no aclara nada,ssh -vT [email protected]para ver qué clave se ofrece y cómo responde el servidor.
2. Permission to equipo/gestor-tareas.git denied to carla
- (a) Autorización. El mensaje nombra a Carla, así que la autenticación ha funcionado perfectamente.
- (b) Su cuenta no tiene permiso de escritura en ese repositorio, o —si va por HTTPS con token— el token carece del ámbito de escritura.
- (c) Revisar los permisos de la cuenta en la configuración del repositorio y los ámbitos del token en la plataforma. No hay ningún comando de Git que arregle esto: es un cambio en el servidor.
3. Support for password authentication was removed
- (a) Autenticación. Se está enviando un método que el servidor ya no admite.
- (b) Se ha tecleado la contraseña de la cuenta en lugar de un token; o hay una credencial antigua guardada en el gestor, con la contraseña de antes de la migración.
- (c) Generar un token con el ámbito necesario y, muy importante, borrar la credencial guardada antes de reintentar, o el gestor volverá a enviar la vieja:
# Eliminar la credencial almacenada para ese servidor
printf "protocol=https\nhost=git.ejemplo.es\n\n" | git credential reject4. REMOTE HOST IDENTIFICATION HAS CHANGED!
- (a) Autenticación, pero en el sentido inverso: es el servidor el que no consigue demostrar su identidad ante ti.
- (b) El servidor se ha reinstalado o la plataforma ha rotado sus claves (lo normal); o alguien está interceptando la conexión (lo grave).
- (c) Obtener la huella actual y compararla con la publicada oficialmente antes de tocar nada:
Solo si coincide con la oficial: ssh-keygen -R git.ejemplo.es y reconectar.
5. connect to host … port 22: Connection timed out
- (a) Ninguna de las dos: es un problema de red. La conexión no llega a establecerse, así que no hay ni autenticación ni autorización.
- (b) Un cortafuegos corporativo con el puerto 22 cerrado (lo más habitual con diferencia), o el servidor caído.
- (c) Comprobar la conectividad y, si es el cortafuegos, cambiar de vía:
# ¿Llega algo al puerto 22?
nc -zv git.ejemplo.es 22
# Solución práctica: pasar a HTTPS
git remote set-url origin https://git.ejemplo.es/equipo/gestor-tareas.gitAlgunas plataformas ofrecen además SSH por el puerto 443, que atraviesa esos cortafuegos:
Conclusión
Con esta lección el equipo puede por fin hablar con el servidor. Lo esencial:
- Leer un repositorio público no requiere credenciales; escribir siempre sí, porque
pushmodifica las referencias del servidor. user.nameyuser.emailno autentican nada: son metadatos del commit. La identidad de acceso vive en otra capa.- Autenticación (quién eres) y autorización (qué puedes hacer) son distintas.
Permission denied (publickey)es lo primero;403 Forbiddenes lo segundo. Distinguirlas dirige el diagnóstico. - HTTPS se autentica con un token personal de acceso, que sustituyó a la contraseña por ser de ámbito limitado, revocable, caducable, auditable y compatible con doble factor. Concede siempre el ámbito mínimo y usa un token por máquina.
- SSH se autentica con un par de claves: la privada nunca sale de tu disco, la pública se sube al servidor. Genera con
ssh-keygen -t ed25519 -C "descripción", pon passphrase, sube el fichero.pub, prueba conssh -Ty usassh-agentpara teclearla una sola vez. ~/.ssh/configresuelve el caso de varias identidades, incluso dos cuentas en el mismo servidor, mediante alias inventados.IdentitiesOnly yesevita elToo many authentication failures.- HTTPS frente a SSH: HTTPS gana en cortafuegos corporativos y en granularidad de permisos; SSH gana en comodidad diaria, en no caducar y en manejar varias identidades. Cambiar de uno a otro es un
git remote set-url. - Cada sistema tiene su gestor de credenciales:
libsecreten Linux,osxkeychainen macOS y Git Credential Manager en Windows, que además abre el navegador y gestiona los tokens por ti: el camino de Carla. credential.helper storeguarda el token en texto plano en~/.git-credentials. Evítalo en máquinas reales; si no hay llavero,cachecon tiempo de espera es mejor opción.- Para lo demás —firma de commits, gestión de secretos, credenciales filtradas en el historial— la lección 08-05.
Lo que viene
Ana, Bruno y Carla ya pueden autenticarse. El canal está abierto en los dos sentidos y, por primera vez en el curso, los objetos pueden viajar de un .git/ a otro.
En la lección 04-04: Obteniendo y Extrayendo Cambios empezamos a usarlo en el sentido de la recepción, y atacamos de frente la confusión más extendida de Git: la diferencia entre git fetch y git pull. Veremos por qué fetch no toca jamás tu directorio de trabajo, qué es FETCH_HEAD, cómo inspeccionar lo que ha llegado antes de integrarlo, y los distintos modos de git pull. Y por fin Carla clona gestor-tareas y se pone al día con el trabajo de sus compañeros.
Dominando Git: De Principiante a Avanzado
Módulo 1: Introducción a Git
- ¿Qué es Git?
- Instalando Git
- Terminología Básica de Git
- El Modelo de Datos de Git
- Configurando Git
- Configuración Inicial
Módulo 2: Operaciones Básicas de Git
- Creando un Repositorio
- Clonando un Repositorio
- Flujo de Trabajo Básico de Git
- Preparando y Confirmando Cambios
- Inspeccionando Cambios con git diff
- Visualizando el Historial de Confirmaciones
Módulo 3: Ramas y Fusión
- Entendiendo las Ramas
- Creando y Cambiando Ramas
- Fusionando Ramas
- Estrategias de Fusión
- Resolviendo Conflictos de Fusión
- Gestión de Ramas
Módulo 4: Trabajando con Repositorios Remotos
- Entendiendo los Repositorios Remotos
- Agregando un Repositorio Remoto
- Autenticación con Repositorios Remotos
- Obteniendo y Extrayendo Cambios
- Enviando Cambios
- Rastreando Ramas
Módulo 5: Operaciones Avanzadas de Git
- Rebase
- Rebase Interactivo
- Cherry-Picking de Confirmaciones
- Guardando Cambios Temporales
- Etiquetando Confirmaciones
- Revirtiendo Confirmaciones
Módulo 6: Herramientas y Técnicas de Git
- Usando Git Hooks
- Git Bisect
- Git Blame
- Git Log y Alias
- Submódulos de Git
- Múltiples Copias de Trabajo con git worktree
Módulo 7: Estrategias de Colaboración y Flujo de Trabajo
- Forks y Pull Requests
- Revisiones de Código con Git
- Flujo de Trabajo Git Flow
- GitHub Flow
- Trunk Based Development
- Integración Continua con Git
Módulo 8: Mejores Prácticas y Consejos de Git
- Escribiendo Buenos Mensajes de Confirmación
- Manteniendo un Historial Limpio
- Ignorando Archivos con .gitignore
- Atributos de Fichero con .gitattributes
- Mejores Prácticas de Seguridad
- Consejos de Rendimiento
Módulo 9: Solución de Problemas y Depuración
- Problemas Comunes de Git
- Deshaciendo Cambios
- Resolviendo Divergencias con el Remoto
- Recuperando Confirmaciones Perdidas
- Tratando con Repositorios Corruptos
- Técnicas Avanzadas de Depuración
