Seguridad en Proxmox: Tokens API bien hechos (para que la contraseña root deje de ser un arma)

¿Te fue útil?

Los tokens API son la forma de dejar de tratar la contraseña root como una llave maestra que todo el mundo toma prestada. Bien implementados, son con alcance, revocables, auditables y aburridos. Ser aburrido es la meta.

Lo que realmente estás asegurando (y por qué las contraseñas siguen fallando)

Proxmox no es “solo un hipervisor.” Es tu plano de control: acciones de encendido, cableado de almacenamiento, cambios de red, consolas de VM, snapshots, replicación, copias de seguridad, reglas de firewall e identidades de usuario. Si alguien puede acceder a la API de Proxmox con permisos amplios, no necesita “hackear” tus VMs. Puede convertirse en tu equipo de plataforma.

Las contraseñas root fallan de formas previsibles:

  • Se propagan. Una contraseña se convierte en un secreto compartido entre humanos y máquinas.
  • No tienen alcance. No puedes decir “esta automatización solo puede arrancar/detener estas VMs y leer estas métricas” con una contraseña.
  • Son difíciles de rotar. Rotarlas rompe scripts. La gente pospone. Los atacantes no.
  • Difuminan la responsabilidad. “root lo hizo” no es un rastro de auditoría, es un encogimiento de hombros.

Los tokens API no arreglan la cultura automáticamente, pero hacen que el buen comportamiento sea más barato que el malo. Los tokens pueden tener alcance y rotarse sin que humanos tengan que reescribir secretos a las 2 a.m. Pueden crearse por app, por pipeline, por integración. Los tokens pueden morir sin arrastrar a toda la organización a una espiral de reseteo de contraseñas.

Hechos y contexto que cambian decisiones

Aquí hay hechos concretos—algunos históricos, otros arquitectónicos—que deberían influir en cómo diseñas el acceso a Proxmox:

  1. Proxmox VE centraliza el control vía una API REST. La interfaz web es esencialmente un cliente de la API. Si puedes hacerlo en la UI, normalmente puedes hacerlo por API—y los scripts lo harán.
  2. Los tokens API son por usuario, no identidades independientes. En Proxmox, los tokens se colocan bajo una identidad de usuario; tu diseño RBAC sigue siendo importante.
  3. RBAC en Proxmox se construye alrededor de roles y rutas de ACL. Si no entiendes el alcance por ruta (como /vms/100 vs /), o romperás la automatización o le darás más permisos de los necesarios.
  4. “Mínimo privilegio” se volvió mainstream porque la seguridad perimetral falló repetidamente. Cuando las redes dejaron de ser “confiables por dentro”, las credenciales con alcance se volvieron la única suposición sensata.
  5. Credential stuffing es viejo, eficaz y aburrido. Los atacantes reusan contraseñas filtradas porque sigue funcionando. Las contraseñas root son especialmente reutilizables porque los humanos las repiten de formas muy humanas.
  6. La respuesta a incidentes funciona con revocación. Rotar contraseñas es lento; revocar tokens es rápido. Lo rápido gana durante la contención.
  7. La auditabilidad es una característica, no teatro de cumplimiento. Cuando una VM se destruye, quieres “qué token” y “qué servicio” no “qué admin quizá”.
  8. La automatización aumenta el radio de daño si no intentas reducirlo deliberadamente. Los sistemas CI a menudo ejecutan con “cluster admin” porque es fácil. Lo fácil es cómo los incidentes se vuelven multi-sitio.

Broma #1: Una contraseña root compartida es como un cepillo de dientes comunitario—técnicamente funcional, moralmente cuestionable y no quieres saber por dónde ha pasado.

Modelo de amenazas: los tres atacantes que realmente tienes

Los consejos de seguridad se vuelven raros cuando están diseñados para villanos de película. Mantengámoslo operativo. En entornos reales, el acceso a Proxmox suele fallar por una de estas razones:

1) El ingeniero interno bienintencionado con demasiado acceso

Esto no es un defecto de carácter; es un defecto del sistema. Si la forma más fácil de arreglar un problema es usar root, la gente usará root. El resultado es daño accidental que se parece exactamente a la malicia: discos borrados, reglas de firewall erróneas aplicadas, migración en vivo disparada durante mantenimiento en el nodo equivocado.

2) El runner de automatización comprometido

Tu runner de CI, agente GitOps o “controlador de backups” es una máquina en internet (o al menos en una red). Eventualmente será comprometida o mal configurada. Cuando eso ocurra, la pregunta no es “puede acceder a Proxmox,” sino “¿qué puede hacer una vez dentro?”.

3) El atacante externo que logró un punto de apoyo en otro lugar

La mayoría de los atacantes no comienzan en Proxmox. Comienzan por email, una credencial VPN, un portátil de desarrollador, una app web o una dependencia de la cadena de suministro. Luego pivotean. Proxmox es un jackpot para pivotear: el acceso al plano de control es la ruta más corta hacia persistencia y destrucción.

Tu trabajo es construir un sistema donde la compromisión de un token o un runner no equivalga a la compromisión del clúster.

Tokens API de Proxmox: el modelo, límites y aristas

Los tokens API de Proxmox son credenciales que creas bajo un usuario de Proxmox. Pueden recibir privilegios vía el mismo sistema RBAC y ACL que los usuarios. Los tokens también pueden marcarse como “privilege separation” (significa que no heredan automáticamente todo lo que tiene el usuario). Esa perilla es donde la mayoría de posturas de seguridad se ganan o pierden.

Los tokens no son magia; RBAC es la magia

Si creas tokens para root@pam y les das permisos amplios a nivel de clúster, no has mejorado nada. Solo has cambiado la forma del problema y facilitado la exfiltración: los tokens están diseñados para ser usados por máquinas, así que las máquinas los almacenarán.

El alcance es por ruta, y los errores de ruta son comunes

Las ACL de Proxmox se aplican a rutas como:

  • / (a nivel de clúster)
  • /nodes/<node> (específico de nodo)
  • /vms/<vmid> (específico de VM)
  • /storage/<storage-id> (específico de almacenamiento)
  • /pool/<poolname> (pools de recursos)

La mayoría de incidentes “ups” provienen de otorgar en / porque alguien quería un token para una tarea y no supo encontrar la ruta o el rol correcto. Así que lo hicieron global. Felicidades, acabas de construir un botón de apagado.

El ciclo de vida del token importa más que su creación

Crear tokens es fácil. Administrarlos es donde los programas mueren:

  • ¿Dónde se almacenan los tokens? (secretos de CI, Vault, variables de entorno, archivos en disco.)
  • ¿Con qué frecuencia se rotan?
  • ¿Cómo detectas anomalías en su uso?
  • ¿Cómo revocas en minutos?

Idea parafraseada (Gene Kim): “Mejorar sistemas es acortar bucles de retroalimentación y hacer que los cambios sean seguros de repetir.” Eso aplica también a la rotación de credenciales.

Principios de diseño: mínimo privilegio que sobreviva la vida real

1) Los tokens son por integración, no por equipo

Si existe “el token de DevOps”, has creado destino compartido. Crea tokens por herramienta y por entorno: terraform-prod, backup-controller, monitoring-readonly, ci-staging. Los humanos no deben compartir tokens; las máquinas tampoco.

2) Usa “privilege separation” a menos que hagas explícitamente un token de admin

Por defecto, un token puede heredar los privilegios del usuario (según cómo lo crees). Quieres que el token tenga solo las ACLs que adjuntes explícitamente. El usuario padre puede ser admin para uso de emergencia, mientras el token permanece con alcance para automatizaciones.

3) Prefiere pools de recursos a la proliferación de ACLs por VM

Conceder ACLs en docenas de VMs individuales es cómo terminas con “dalo todo en /” después. Los pools te permiten agrupar recursos y conceder permisos en la ruta del pool. Tu yo futuro te lo agradecerá con menos ediciones a las 2 a.m.

4) Separa funciones: aprovisionamiento no es lo mismo que operación

Las herramientas de aprovisionamiento suelen necesitar derechos para crear VMs, adjuntar almacenamiento, establecer etiquetas y configurar red. Los operadores y sistemas de backup necesitan derechos distintos. No empaquetes todo porque sea “un pipeline”. Los pipelines no son identidades.

5) Diseña para ejercicios de revocación

La revocación no es una maniobra solo para emergencias. Practícala. Debes poder revocar un token y ver una falla controlada en el sistema dependiente, con un mensaje de error claro y un plan de reversión.

6) Diseña pensando en el modo de falla más común: alguien otorga demasiado

Haz que el sobre-permiso sea más difícil:

  • Restringe quién puede editar ACLs en /.
  • Mantén un número reducido de roles predefinidos (y revísalos).
  • Requiere control de cambios para permisos a nivel de clúster.

Broma #2: “Acceso admin temporal” tiene la misma vida útil que una bolsa plástica en el océano.

Tareas prácticas (comandos, salida y decisiones)

Estas son tareas prácticas que puedes ejecutar en un nodo Proxmox o vía las herramientas CLI. Cada una incluye qué significa la salida y la decisión que tomas a partir de ella. La idea es claridad operativa, no seguridad por casilla.

Task 1: Confirmar el estado del clúster antes de cambiar auth

cr0x@server:~$ pvecm status
Cluster information
-------------------
Name:             prod-pve
Config Version:   17
Transport:        knet
Secure auth:      on

Quorum information
------------------
Date:             Tue Feb  4 11:12:21 2026
Quorum provider:  corosync_votequorum
Nodes:            3
Node ID:          0x00000001
Ring ID:          1.24
Quorate:          Yes

Qué significa: Tienes quórum y los cambios de configuración del clúster deberían replicarse correctamente. Si Quorum es No, evita churn en RBAC; podrías crear deriva entre nodos.

Decisión: Procede solo cuando haya quórum. Si no, arregla la salud del clúster primero.

Task 2: Listar usuarios para encontrar “automatización disfrazada de humanos”

cr0x@server:~$ pveum user list
┌──────────────┬───────────┬───────────┬────────────────────────────┐
│ userid       │ enable    │ expire    │ firstname                  │
╞══════════════╪═══════════╪═══════════╪════════════════════════════╡
│ root@pam     │ 1         │ 0         │                            │
│ alice@pve    │ 1         │ 0         │ Alice                      │
│ ci@pve       │ 1         │ 0         │ CI Runner                  │
│ monitor@pve  │ 1         │ 0         │ Monitoring                 │
└──────────────┴───────────┴──────────────┴──────────────┘

Qué significa: Existen usuarios locales. Si ves “cuentas de servicio” como humanos con nombre o viceversa, probablemente tienes proliferación de tokens y propiedad poco clara.

Decisión: Crea usuarios de servicio dedicados (o identidades respaldadas por un realm) para cada integración. No reutilices usuarios humanos para automatización.

Task 3: Inspeccionar tokens API y detectar errores de herencia

cr0x@server:~$ pveum user token list ci@pve
┌──────────────┬───────────────┬────────┬──────────────┐
│ tokenid      │ expire        │ enable │ privsep      │
╞══════════════╪═══════════════╪════════╪══════════════╡
│ terraform    │ 0             │ 1      │ 1            │
│ ansible      │ 0             │ 1      │ 0            │
└──────────────┴───────────────┴────────┴──────────────┘

Qué significa: privsep=0 sugiere que el token puede heredar privilegios del usuario. Eso es frecuentemente cómo el “mínimo privilegio” muere en silencio.

Decisión: Cambia los tokens a separación de privilegios a menos que tengas una razón documentada para no hacerlo. Luego asigna explícitamente las ACL al token.

Task 4: Crear un usuario de servicio dedicado (sin shell, sin extras)

cr0x@server:~$ sudo pveum user add backup@pve --comment "Backup controller service user"

Qué significa: Has creado una identidad que puede contener tokens y ACLs. No es un humano; no debe usarse de forma interactiva.

Decisión: Usa un usuario de servicio por dominio de integración (backup, monitoring, provisioning). Evita “un usuario para gobernarlos a todos”.

Task 5: Crear un token con separación de privilegios y capturarlo una vez

cr0x@server:~$ sudo pveum user token add backup@pve restic --privsep 1
┌──────────────┬──────────────────────────────────────────────┐
│ key          │ value                                        │
╞══════════════╪══════════════════════════════════════════════╡
│ full-tokenid │ backup@pve!restic                            │
│ value        │ 7c9dbbb2-3e76-4b3b-8d9f-0c8af2c5d2a1         │
└──────────────┴──────────────────────────────────────────────┘

Qué significa: Esta es la única vez que verás el valor del token en texto plano. Guárdalo en tu gestor de secretos inmediatamente.

Decisión: Si no puedes almacenar secretos correctamente, para aquí y arregla eso primero. Los tokens amplifican la higiene de secretos que ya tengas.

Task 6: Crear un rol personalizado en lugar de reutilizar “Administrator”

cr0x@server:~$ sudo pveum role add BackupOperator -privs "VM.Audit VM.Backup Datastore.Audit"

Qué significa: Definiste un rol con privilegios explícitos. Las cadenas de privilegios exactas deben coincidir con tu versión de Proxmox y las operaciones previstas.

Decisión: Prefiere roles pequeños con nombres que coincidan con una función de trabajo. Si no puedes explicar un privilegio en una frase, no lo otorgues aún.

Task 7: Aplicar ACLs en una ruta restringida (pool o almacenamiento específico)

cr0x@server:~$ sudo pveum acl modify /pool/prod-vms -token 'backup@pve!restic' -role BackupOperator

Qué significa: El token recibe permisos solo para recursos dentro del pool prod-vms (dependiendo de qué viva allí y cómo operes las copias de seguridad).

Decisión: Si no puedes acotar por pool, probablemente te falte buena organización de recursos. Arregla la organización en lugar de conceder /.

Task 8: Verificar ACLs y detectar concesiones accidentales a nivel de clúster

cr0x@server:~$ pveum acl list
┌───────────────┬───────────────────────┬───────────────┬─────────────┐
│ path          │ ugid                  │ roleid        │ propagate   │
╞═══════════════╪═══════════════════════╪═══════════════╪═════════════╡
│ /             │ root@pam              │ Administrator │ 1           │
│ /pool/prod-vms│ backup@pve!restic     │ BackupOperator│ 1           │
│ /             │ ci@pve!ansible        │ Administrator │ 1           │
└───────────────┴───────────────────────┴───────────────┴─────────────┘

Qué significa: El token ci@pve!ansible tiene Administrator en /. Eso es un problema a menos que sea un riesgo conscientemente aceptado con controles compensatorios.

Decisión: Elimina ACLs amplias para tokens de automatización. Crea roles y rutas acotadas.

Task 9: Eliminar una ACL sobrepotente (de forma segura)

cr0x@server:~$ sudo pveum acl delete / -token 'ci@pve!ansible' -role Administrator

Qué significa: Revocaste cluster-admin de ese token en la ruta raíz.

Decisión: Confirma inmediatamente qué necesita aún la automatización; vuelve a otorgar solo los permisos mínimos requeridos en rutas estrechas.

Task 10: Validar autenticación del token contra el endpoint API local

cr0x@server:~$ curl -k -s \
  -H "Authorization: PVEAPIToken=backup@pve!restic=7c9dbbb2-3e76-4b3b-8d9f-0c8af2c5d2a1" \
  https://127.0.0.1:8006/api2/json/version | jq
{
  "data": {
    "release": "8.1",
    "repoid": "c6d7f9a0",
    "version": "8.1.4"
  }
}

Qué significa: El token es válido y puede alcanzar la API. Esto es una prueba básica de disponibilidad/autenticación.

Decisión: Si esto falla, no empieces a reconfigurar roles ciegamente. Confirma primero sincronización horaria, formato del token y que estás golpeando el nodo/realm correcto.

Task 11: Confirmar autorización intentando una acción que debería denegarse

cr0x@server:~$ curl -k -s \
  -H "Authorization: PVEAPIToken=backup@pve!restic=7c9dbbb2-3e76-4b3b-8d9f-0c8af2c5d2a1" \
  https://127.0.0.1:8006/api2/json/nodes | jq
{
  "errors": {
    "permission": "permission denied - invalid privileges"
  }
}

Qué significa: Bien. Tu token de backup no puede enumerar nodos a nivel de clúster. Eso es el mínimo privilegio funcionando.

Decisión: Manténlo denegado a menos que tu sistema de backup realmente necesite inventario de nodos. Si lo necesita, otorga solo lectura en un alcance más estrecho, no admin.

Task 12: Comprobar acceso SSH de root (porque los tokens API no te salvarán del desvío por SSH)

cr0x@server:~$ sudo sshd -T | egrep 'permitrootlogin|passwordauthentication'
permitrootlogin yes
passwordauthentication yes

Qué significa: Root puede entrar por SSH con contraseña. Eso es una vía de bypass de credenciales alrededor de tu programa de tokens.

Decisión: Desactiva autenticación por contraseña y SSH directo para root. Usa sudo desde cuentas nombradas o usa acceso por consola para emergencias.

Task 13: Aplicar defaults de SSH más seguros (y saber qué cambiaste)

cr0x@server:~$ sudo sh -c 'cat >/etc/ssh/sshd_config.d/99-hardening.conf <

Qué significa: SSH de root está apagado; las contraseñas están apagadas. Si alguien roba una contraseña, es menos útil. Si alguien roba un token, no les ayudará a entrar por SSH.

Decisión: Asegúrate de haber probado el acceso por clave para cuentas de break-glass antes de activar esto en todo el clúster.

Task 14: Comprobar sincronización horaria (a la autenticación por token le encanta la desviación de reloj)

cr0x@server:~$ timedatectl
               Local time: Tue 2026-02-04 11:15:10 UTC
           Universal time: Tue 2026-02-04 11:15:10 UTC
                 RTC time: Tue 2026-02-04 11:15:10
                Time zone: UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Qué significa: El reloj está sincronizado. Cuando no lo está, obtienes fallos intermitentes de autenticación y rarezas TLS que parecen “Proxmox es inestable.” No lo es. Tu hora lo está.

Decisión: Si no está sincronizado, arregla NTP antes de depurar tokens o TLS.

Task 15: Monitorizar auth y errores de API en logs

cr0x@server:~$ sudo journalctl -u pveproxy -u pvedaemon --since "30 min ago" | tail -n 20
Feb 04 10:58:22 pve1 pveproxy[1832]: authentication failure; rhost=10.20.1.55 user=backup@pve msg=invalid token value
Feb 04 11:02:17 pve1 pvedaemon[1711]: api call failed: permission denied - invalid privileges
Feb 04 11:07:44 pve1 pveproxy[1832]: successful auth for user 'monitor@pve' from 10.20.2.20

Qué significa: Puedes distinguir valores de token inválidos de privilegios insuficientes. Esa diferencia importa: una es distribución de secretos, la otra es diseño RBAC.

Decisión: Si “invalid token value,” rota y arregla el manejo de secretos. Si “invalid privileges,” ajusta rutas/roles de ACL, no el almacenamiento del token.

Task 16: Encontrar qué proceso escucha en el puerto API de Proxmox

cr0x@server:~$ sudo ss -ltnp | grep ':8006'
LISTEN 0      4096         0.0.0.0:8006      0.0.0.0:*    users:(("pveproxy",pid=1832,fd=6))

Qué significa: pveproxy está escuchando en 8006. Si ves otra cosa, tienes un problema de empaquetado o proceso.

Decisión: Si pveproxy no está escuchando, no culpes a los tokens. Arregla el servicio primero.

Task 17: Rotar un token sin downtime (patrón)

cr0x@server:~$ sudo pveum user token add backup@pve restic-v2 --privsep 1
┌──────────────┬──────────────────────────────────────────────┐
│ key          │ value                                        │
╞══════════════╪══════════════════════════════════════════════╡
│ full-tokenid │ backup@pve!restic-v2                         │
│ value        │ 5c1a4e61-9b9c-4f1f-9c7f-9d7a1b4a8d20         │
└──────────────┴──────────────────────────────────────────────┘
cr0x@server:~$ sudo pveum acl modify /pool/prod-vms -token 'backup@pve!restic-v2' -role BackupOperator
cr0x@server:~$ sudo pveum user token list backup@pve
┌──────────────┬───────────────┬────────┬──────────────┐
│ tokenid      │ expire        │ enable │ privsep      │
╞══════════════╪══════════════════════════════════════════════╡
│ restic       │ 0             │ 1      │ 1            │
│ restic-v2    │ 0             │ 1      │ 1            │
└──────────────┴──────────────┴───────────────┴──────────────┘

Qué significa: Ahora tienes dos tokens válidos con ACLs idénticas. Actualiza el sistema dependiente para usar v2, verifica, y luego revoca v1.

Decisión: Siempre rota por solapamiento, no por corte, a menos que disfrutes llamarte a ti mismo por la noche.

Task 18: Revocar un token limpiamente durante un incidente

cr0x@server:~$ sudo pveum user token remove backup@pve restic
cr0x@server:~$ sudo pveum user token list backup@pve
┌──────────────┬───────────────┬────────┬──────────────┐
│ tokenid      │ expire        │ enable │ privsep      │
╞══════════════╪═══════════════╪════════╪════════──────╡
│ restic-v2    │ 0             │ 1      │ 1            │
└──────────────┴──────────────┴───────────────┴──────────────┘

Qué significa: El token comprometido está muerto. Las llamadas que lo usen deberían empezar a fallar inmediatamente.

Decisión: Después de la revocación, revisa logs por intentos continuos. Si los intentos continúan, has encontrado el runner comprometido o la ubicación filtrada del secreto.

Guion rápido de diagnóstico

Cuando “el token no funciona” o “la automatización está rota,” no divagues. Sigue una secuencia que aísle el cuello de botella en minutos.

Primero: ¿la API es alcanzable y está sana?

  • Comprueba ss -ltnp | grep :8006 para asegurar que pveproxy esté escuchando.
  • Revisa systemctl status pveproxy pvedaemon por bucles de crash.
  • Desde el host runner, prueba conectividad a node:8006 (firewall/ruteo).

Interpretación: Si el puerto está caído o los servicios están inestables, los cambios en tokens no importarán. Arregla la salud de la plataforma primero.

Segundo: ¿falla autenticación o autorización?

  • Mira journalctl -u pveproxy -u pvedaemon por “invalid token value” vs “invalid privileges”.
  • Prueba una llamada API simple como /api2/json/version.

Interpretación: Invalid token value = manejo/formatado de secretos. Invalid privileges = diseño RBAC/ACL.

Tercero: ¿has acotado la ACL a la ruta correcta?

  • Lista ACLs y busca dónde se otorgó el token.
  • Confirma que el recurso realmente esté bajo ese pool/ruta.
  • Revisa que el rol tenga los privilegios suficientes pero no amplios.

Interpretación: La mayoría de fallos de mínimo privilegio son por ruta equivocada. El segundo motivo más común son cadenas de privilegios incorrectas en el rol.

Cuarto: ¿la “separación de privilegios” hace lo que crees?

  • Lista tokens y confirma privsep=1.
  • Comprueba si accidentalmente otorgaste demasiado al usuario padre en / y confiaste en la herencia.

Interpretación: Si un token está sobrepotenciado, suele ser porque heredó algo o se le otorgó en /.

Quinto: ¿la hora/TLS causa fallos intermitentes de auth?

  • Comprueba timedatectl en nodos y runners.
  • Si los runners validan TLS, confirma la cadena de confianza del certificado y que el hostname coincida.

Interpretación: Desviación de reloj y desajuste TLS se hacen pasar por “token malo”, especialmente durante reconstrucciones de nodos.

Errores comunes: síntomas → causa raíz → corrección

1) Síntoma: “Todo funciona en la UI web, pero el token recibe permiso denegado”

Causa raíz: Probaste como usuario humano (que tiene privilegios amplios) y asumiste que el token los hereda. El token es privsep=1 sin ACLs, o las ACLs están en la ruta equivocada.

Corrección: Adjunta ACLs al token explícitamente en la ruta correcta; valida con una llamada API mínima que requiera exactamente el privilegio.

2) Síntoma: “El token funciona un día, luego falla aleatoriamente”

Causa raíz: El valor del token fue rotado en el almacén de secretos pero no desplegado en todas partes; o múltiples runners tienen valores antiguos; o la desviación de reloj provoca comportamientos en el borde de autenticación.

Corrección: Implementa rotación por solapamiento; añade una comprobación de despliegue que confirme que el token funciona antes del rollout; aplica NTP en todas partes.

3) Síntoma: “La automatización puede borrar VMs aunque no debería”

Causa raíz: El token tiene Administrator en / (a menudo porque alguien lo habilitó para debug y nunca lo quitó), o herencia del usuario admin está activada para el token.

Corrección: Quita la ACL en la ruta raíz; recrea el token con --privsep 1; crea roles estrechos como “VM.PowerMgmt” solamente.

4) Síntoma: “Revocar el token no detuvo el comportamiento”

Causa raíz: El actor no está usando ese token (suposición errónea), o hay múltiples tokens, o usan una ruta por contraseña/SSH en su lugar.

Corrección: Busca en los logs por la identidad del usuario/token; inventaría todos los tokens; deshabilita rutas de acceso por contraseña; revoca sistemáticamente.

5) Síntoma: “No podemos acotar permisos sin romper el pipeline”

Causa raíz: El pipeline hace demasiado: aprovisionamiento, firewall, almacenamiento y operaciones VM bajo una sola identidad. O falta organización de recursos (sin pools, nombres inconsistentes).

Corrección: Divide identidades por función y etapa; crea pools; rediseña pasos del pipeline para que cada uno use un token específico.

6) Síntoma: “Los tokens se filtran en logs”

Causa raíz: Las herramientas imprimen encabezados, variables de entorno o salida de depuración; ingenieros copian y pegan comandos fallidos en chats.

Corrección: Desactiva logging HTTP verboso; limpia logs de CI; usa secretos enmascarados; aplica una política operativa de “no secretos en tickets” con soporte de herramientas.

Tres mini-historias corporativas (todas muy plausibles)

Mini-historia 1: El incidente causado por una suposición equivocada

Tenían un clúster Proxmox soportando servicios internos: agentes de construcción, almacenamiento de artefactos, algunas bases de datos pequeñas que todos juraban que eran “temporales”. El equipo de plataforma decidió “hacer lo correcto” y movió la automatización de una contraseña root a un token API.

La suposición equivocada: “Si el usuario puede hacerlo en la UI, el token también podrá.” Crearon un token bajo un usuario admin, activaron privilege separation porque sonaba más seguro, y nunca adjuntaron ACLs al token. El usuario tenía todo. El token tenía casi nada.

A medianoche, su sistema CI intentó crear una VM para un despliegue y recibió permiso denegado. La lógica de reintento fue entusiasta. Martilló la API, llenó logs, y el on-call vio alertas de “fallo de autenticación Proxmox” y asumió compromiso. Empezaron a revocar credenciales y rompieron otras integraciones, porque el primer modelo mental fue “ataque”, no “token mal dimensionado”.

Lo que lo arregló no fueron heroicidades. Fue leer los logs con atención: “invalid privileges,” no “invalid token value.” Adjuntaron el rol correcto en la ruta del pool, luego limitaron la tasa de reintentos del pipeline. La lección mayor fue cultural: cuando cambias auth, trátalo como un despliegue de producción con rollout por fases, no como un ajuste de UI.

Mini-historia 2: La optimización que salió mal

Otra compañía quería aprovisionamiento más rápido. Su pipeline de Terraform creó VMs, puso tags, adjuntó ISOs, configuró reglas de firewall e incluso hizo tareas de mantenimiento de nodos. Todo mediante un token. Era rápido porque era efectivamente cluster-admin.

“Optimizaron” más almacenando el token en una imagen de runner compartida para que los jobs no tuvieran que obtener secretos en tiempo de ejecución. Esto recortó segundos de las builds. También significó que cada runner efímero tenía una copia del token en disco, y las imágenes antiguas vivían en registros y caches más tiempo del que alguien admitía.

Meses después, una revisión de seguridad encontró el token en una capa de imagen. No por forense avanzado—porque alguien ejecutó strings en una imagen durante un escaneo rutinario y salió como una confesión. Revocaron el token. La mitad de su automatización dejó de funcionar. La otra mitad siguió funcionando porque tenía un segundo token codificado en otro lugar, dejado por una migración anterior.

Lo peor no fue solo la exposición; fue la pérdida de control. No sabían dónde estaban los secretos. No podían rotar limpiamente. Ni siquiera podían inventariar. Tras la limpieza, su pipeline fue un poco más lento, pero su tiempo de respuesta a incidentes mejoró drásticamente. La velocidad es buena; la revocación predecible es mejor.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Otra organización corría Proxmox para cargas de trabajo edge. Nada glamuroso. Muchos clústeres pequeños. Mucha automatización. Hicieron una cosa aburrida de forma consistente: cada token tenía un propietario, un propósito, un alcance y una fecha de rotación. Guardaban estos metadatos en un registro interno simple y practicaban la rotación trimestralmente.

Una mañana, el monitoreo mostró actividad inusual en la API: repetidos intentos de permiso denegado desde un host que no debería comunicarse con Proxmox. Los logs tenían un ID de token en la cabecera de autenticación. Encontraron el token exacto en el registro: pertenecía a un runner CI de staging, acotado a un pool de staging, y no debía usarse desde ese segmento de red.

Lo revocaron inmediatamente, y nada crítico en producción se rompió porque el token estaba acotado y era solo de staging. Luego rastrearon el host del runner: había sido reimaged y colocado accidentalmente en una red más amplia. Ese fue el verdadero fallo. El diseño de tokens convirtió una señal alarmante en un incidente contenido.

Su práctica “aburrida” no fue cara. Fue disciplinada. Evitó que un error de staging se convirtiera en un outage de producción y les regaló un martes tranquilo en lugar de una llamada ejecutiva.

Listas de verificación / plan paso a paso

Paso a paso: mover una integración de la contraseña root a un token con alcance

  1. Inventaria el acceso actual. Identifica dónde se usa la contraseña root (variables de CI, scripts, cron jobs, gestión de configuración).
  2. Crea un usuario de servicio dedicado. Nómbralo por la integración, no por una persona (por ejemplo, backup@pve).
  3. Crea un token con separación de privilegios. Guarda el valor del token una vez en un gestor de secretos.
  4. Crea o reutiliza un rol estrecho. Solo los privilegios requeridos para la integración.
  5. Acota las ACLs por pool/almacenamiento/ruta. Evita / salvo que sea realmente una integración admin de clúster (raro).
  6. Prueba con una llamada API mínima. Valida auth (/version), luego una llamada autorizada y después una denegada.
  7. Despliega en un canary. Un runner, un entorno, un job.
  8. Habilita rotación por solapamiento desde el día uno. Añade token v2, despliega, verifica, revoca v1.
  9. Elimina el uso de la contraseña antigua. Bórrala de secretos, scripts, imágenes; no dejes credenciales “backup” tiradas.
  10. Documenta propiedad y caducidad/rotación. Si no tiene dueño, se volverá inmortal.

Lista: cómo se ve “bien”

  • La contraseña root no la usa la automatización.
  • SSH root está deshabilitado; autenticación por contraseña deshabilitada donde sea posible.
  • Los tokens usan separación de privilegios por defecto.
  • Los tokens están acotados a pools, VMs, IDs de almacenamiento o nodos—no a /.
  • Los roles son pequeños, nombrados y revisados periódicamente.
  • Existe inventario de tokens (propietario, propósito, creado, última rotación).
  • La rotación se practica, no se promete.
  • Los logs distinguen rápidamente secretos malos de permisos malos.

Lista: contención de incidentes por sospecha de compromiso de credenciales

  1. Identifica el token/usuario en los logs (pveproxy/pvedaemon).
  2. Revoca el token inmediatamente (no “esperes confirmación”).
  3. Busca intentos continuos de usar el token revocado.
  4. Localiza el punto de distribución del secreto (CI, configuración, disco).
  5. Rota tokens adyacentes usados en el mismo runner o gestor de secretos.
  6. Confirma que no existan ACLs amplias en / para tokens de automatización.
  7. Revisa acciones recientes en la API (quién hizo qué, desde dónde) y valida la integridad de VMs y almacenamiento.

Preguntas frecuentes

1) ¿Debo crear tokens bajo root@pam?

No para automatización. Usa usuarios de servicio dedicados y separación de privilegios. Root debe ser para acceso humano de emergencia, no CI.

2) ¿Qué me da realmente la “separación de privilegios”?

Evita que el token herede automáticamente los permisos del usuario. Te obliga a otorgar explícitamente lo que el token necesita, que es la idea principal.

3) ¿Puedo restringir un token a una VM específica?

Sí, aplicando ACLs en /vms/<vmid> con un rol estrecho. En la práctica, los pools escalan mejor, pero por-VM es útil para sistemas de alto riesgo.

4) ¿Cómo roto tokens sin romper producción?

Usa rotación por solapamiento: crea un segundo token con ACLs idénticas, despliega, verifica y luego revoca el antiguo. No “intercambies” a menos que toleres downtime.

5) ¿Los tokens reemplazan la autenticación de dos factores (2FA)?

No. Los tokens son para máquina a máquina. 2FA es para humanos. Quieres ambos: controles fuertes para accesos humanos y credenciales con alcance para máquinas.

6) ¿Cuál es el lugar más seguro para guardar tokens?

Un gestor de secretos adecuado con políticas de acceso y logs de auditoría. Si debes usar variables de secretos de CI, asegura el enmascarado y que los logs de depuración no impriman cabeceras.

7) ¿Por qué no poner Proxmox detrás de una VPN y seguir usando contraseñas?

Porque las redes internas y las VPN ya no son límites de confianza. Necesitas credenciales acotadas y revocables incluso cuando la red es “privada.” VPN es una capa, no una estrategia.

8) ¿Cuántos roles deberíamos tener?

Menos de los que crees, pero más de uno. Comienza con 5–10 roles enfocados en trabajo (monitoring solo lectura, control de encendido VM, provisioning, backup, admin de red). Expande solo cuando no puedas expresar una necesidad claramente.

9) ¿Qué pasa si una integración necesita acceso amplio a muchas VMs?

Agrupa esas VMs en un pool y acótalo a /pool/<name>. Si realmente necesita permisos a nivel de clúster, trata ese token como una credencial admin de producción: controles extra, rotación más corta, almacenamiento más seguro y aprobación explícita.

10) ¿Cómo sé qué tokens existen y quién los posee?

Proxmox puede listar tokens, pero la propiedad es un problema de proceso. Mantén un registro interno (incluso una tabla simple) que mapee IDs de tokens a propietarios, sistemas y cadencia de rotación.

Conclusión: próximos pasos que realmente perduran

Los tokens API no son un trofeo de seguridad. Son una forma de hacer que la compromisión sea manejable y las operaciones sensatas. Si mantienes la contraseña root como credencial predeterminada para automatización, estás efectivamente diciéndole a los atacantes—y a los ingenieros cansados—que el plano de control está a una filtración de secreto de distancia.

Próximos pasos prácticos:

  1. Elige una integración (CI, backup, monitoring) y muévela a un usuario de servicio dedicado + token con separación de privilegios esta semana.
  2. Crea un rol estrecho que coincida con el trabajo real de esa integración, no con tus miedos.
  3. Acota la ACL a un pool o rutas específicas. Elimina cualquier concesión de Administrator en / para tokens de automatización.
  4. Desactiva login SSH root y autenticación por contraseña donde sea factible, y verifica que aún tengas un camino de break-glass funcional.
  5. Implementa rotación por solapamiento y realiza un ejercicio de rotación. Trátalo como un deploy: por fases, probado y reversible.
  6. Empieza un inventario de tokens con propietarios y fechas de rotación. Si no puedes nombrar al propietario, no tienes un token—tienes una responsabilidad.

Si haces solo una cosa: deja de permitir que “root en todas partes” sea el camino más fácil. Reemplázalo por tokens acotados y un rastro de auditoría que diga la verdad.

← Anterior
«Este dispositivo no puede iniciarse (Código 10)»: pasos de reparación que realmente ayudan
Siguiente →
Instalación de Pop!_OS 24.04 LTS: controladores NVIDIA, Secure Boot y un escritorio limpio

Deja un comentario