Skip to content
victor·stein
0%
booting ~/
./blog / infra / seed-bootstrap
bootstrapyubikeygpg

Evité la Mac que quería por no migrar

VS Victor Stein · 18 abr 2026 · 5 min de lectura

Tenía una MacBook Pro M1 en la que había vivido por años, y una Mac mini M4 Pro que no terminaba de comprar. Cada vez que me emocionaba con el upgrade — más RAM, más máquina — me acordaba de lo que viene después de desempacar: portar mi vida entera a la nueva. Y cerraba la pestaña.

Lo molesto es que ni siquiera quería mover mis cosas. Quería lo contrario — una pizarra limpia, sin el bloat que se va acumulando después de instalar cien apps que usaste una sola vez. Pero “pizarra limpia” hecha a mano es un fin de semana brutal: reinstalar todo, cazar cada credencial, acordarte de cada config que pusiste una vez y olvidaste. Sabía que ese fin de semana me esperaba, así que seguía posponiendo una compra que sí quería.

Entonces llegó el pensamiento obvio: ¿y si un solo curl | bash pudiera portar todo mi tooling y todas mis credenciales a una máquina nueva, y nunca más tuviera que pensar en ello?

El tooling era fácil. Las credenciales eran el problema.

Daily-drive la terminal, así que “mi setup” es básicamente una lista de paquetes de brew y mis dotfiles — problema resuelto. La mitad difícil eran las credenciales. No podés simplemente hacer git clone de tus llaves SSH y GPG a una máquina nueva; eso es justo lo que más necesitás proteger.

Pero tenía una ventaja. Ya guardo mis contraseñas y OTPs en pass, el gestor de contraseñas de unix, que encripta todo con una llave GPG. Así que todo el problema de restaurar secretos se reduce a una pregunta: ¿cómo meto mi llave GPG en una máquina en blanco de forma segura? pass se apoya en Pretty Good Privacy, así que encriptaría el bundle de la llave de la misma forma (ba dum tss).

Quedaba algo feo: todo lo que poseo, detrás de una sola passphrase que tenía que memorizar, commiteada — encriptada — a un repo. Eso se sentía turbio. Una contraseña memorizada es el eslabón débil de todo sistema: se reutiliza, se olvida, o te la ven por encima del hombro. No quería que toda mi identidad digital dependiera de un string que vive en mi cabeza.

Dos cosas que no me podía sacar de la cabeza

Idempotencia. No me hacía ilusiones — este script iba a fallar en la primera corrida, y seguramente en la quinta. Necesitaba correrlo una y otra vez sin que hiciera un desastre cada vez, lo que significaba que necesitaba una máquina para probar. La Mac mini todavía no llegaba. Así que miré mi servidor de casa y pensé: ¿por qué no hacer que esto corra también en Linux? Todo es unix; los comandos en su mayoría se trasladan con un par de salvedades. El soporte multi-OS no fue un gran plan — fue que necesitaba un banco de pruebas antes de que llegara el hardware de verdad.

Seguridad mejor que una contraseña memorizada. Y aquí el universo fue raramente generoso: cayó un swag drop de mi empleador, y en su tienda había YubiKeys. Agarré una y me fui de cabeza al agujero de las llaves físicas.

El diseño que salió de ahí: hacer de la YubiKey la estrella del show. La passphrase que desencripta el bundle no está en mi cabeza — vive en el slot de static-password de la YubiKey. El script pide la passphrase; yo toco la llave en vez de escribirla. Y como una sola llave física es un solo punto de falla, el respaldo es mi Flipper Zero — que llevaba años tirado sin hacer nada — guardando el mismo secreto. Dos dispositivos físicos, cero contraseñas memorizadas.

Cómo corre en realidad

Todo es un solo comando:

curl -fsSL https://raw.githubusercontent.com/victorstein/seed/main/bootstrap.sh | bash

Corrélo con --dry-run primero y te imprime exactamente lo que va a hacer sin tocar nada — el mismo instinto de idempotencia, pero apuntado al usuario en vez de al script. Después, en orden:

  1. Instala las Xcode command-line tools y Homebrew.
  2. Importa mi llave GPG — este es el momento YubiKey. Pide la passphrase y yo toco la llave en vez de escribir.
  3. Restaura mis llaves SSH desde el bundle encriptado.
  4. Clona mis dotfiles y los enlaza en su lugar.
  5. Instala todos los paquetes de brew.

El orden no es arbitrario. GPG va primero porque es la llave que desbloquea todo lo demás — pass, SSH, todo. SSH después, para que la máquina pueda hablar con mis repos. Luego los dotfiles y los paquetes, las partes que son tediosas más que sensibles. Equivocá el orden y el paso 4 no puede autenticarse para clonar nada.

Y corre en macOS y Linux — que, otra vez, solo existe porque necesitaba dónde probarlo.

La ironía, y dónde está

Terminé la encriptación, la idempotencia y el soporte multi-OS en unos dos días. La migración que venía temiendo era supuestamente un fin de semana; me pasé más o menos lo mismo construyendo lo que hizo desaparecer ese fin de semana — y me fui con una habilidad reutilizable y una máquina reproducible en vez de solo una laptop configurada. Ese trato lo acepto siempre.

El bonus que no vi venir del todo: no es una herramienta de una sola vez. Cada nodo nuevo que agrego a mi servidor de casa queda listo — tooling y credenciales — en minutos. Hasta ahora seed ha arrancado cuatro máquinas: dos nodos en mi servidor de casa, la nueva Mac mini que por fin me dejé comprar, y una máquina remota que pago.

El secreto que desbloquea todo vive en tres lugares, ninguno de ellos mi memoria: la YubiKey que toco, la Flipper Zero de respaldo y — último recurso — el mismo string estático escrito y guardado en una bóveda offline, lejísimos de cualquier computadora. Ese string es lo único que de verdad no me puedo dar el lujo de perder. Todo lo demás lo puedo reconstruir en lo que se tarda un café.

bootstrapyubikeygpgdotfilesmacos ← todas las entradas
SIGUIENTE →
Un amigo tacaño, mi Plex y mi primer OpenTofu