Skip to content

CT217: cobertura de backup declarada y observada

20 de octubre de 2026. Sólo fuentes y cuatro llamadas PVE autorizadas desde pmx2: recursos217, config217 filtrada, jobs y una consulta de snapshots. Sin backup, sync, verify, restore, drill, SQL/export, NAS walk, lectura de payload/secretos o cambios runtime. Sólo se redactó este informe.

Declaración runtime, 02:45:36.705338 CEST

CT217 figura running en proxmox2. Su config proyectada contiene rootfs zfs-ha:subvol-217-disk-0, size40G; ningún mpN declarado. Se descartaron env y campos lxc.*. /opt/observa y /home/monxas/appdata son rutas de guest bajo el rootfs declarado, sin un mount point PVE separado declarado para ellas; esto no descarta submontajes manuales, NFS interno o exclusiones de paths.

Job que selecciona217 enabled schedule storage Selección/exclusión
backup-lxc-terra 1 01:00 pbs vmid217 explícito, no excluido, nodo compatible

Es el único job seleccionante observado; no quedaron selecciones pool sin resolver. No se copiaron targets ajenos ni se crea otro scheduler. Declaración de job no equivale a ejecución satisfactoria.

Snapshots listados, 02:46:41.579069 CEST

La llamada adicional exacta fue /nodes/proxmox2/storage/pbs/content --content backup --vmid217. Se conservaron hasta tres entradas recientes; la respuesta contenía dos:

Volid ctime CEST size informado
pbs:backup/ct/217/2026-10-19T23:02:36Z 20oct01:02:36 19.924.189.387 B (~18,56 GiB)
pbs:backup/ct/217/2026-10-19T07:08:28Z 19oct09:08:28 17.079.081.109 B (~15,91 GiB)

Edad del último ctime: 1h44m05,58s. Size es metadata API, no uso deduplicado ni bytes verificados. No se consultaron worker status/endtime, integridad ni contenido. Los snapshots listados no prueban restore, coherencia de aplicaciones o inclusión de cada ruta.

El último ctime precede a Required instalada a las02:12: no se acredita que ese snapshot contenga esa versión; tampoco se infiere su exclusión sin payload/intervalo del job. La regla tiene su fuente Git. La auditoría anterior registraba a las23:02 «28 invitados con copia PBS<26h»: evidencia agregada reciente compatible con217, no un restore suyo.

Matriz de configuración y persistencia

El perfil declara diez servicios y 16 binds Docker absolutos: siete de configuración/secretos y nueve de datos. Un Docker bind dentro del guest no es por ello un mount PVE externo excluido de vzdump. Para todos los paths siguientes rige la condición rootfs anterior, sin comprobación de payload:

Paths de guest Fuente disponible / límite de recuperación
/opt/observa/compose.yaml Perfil/hash e identidades de imágenes; no Compose completo ni bindings de secretos reconstruidos
/opt/observa/conf/prometheus.yml Template reconciliado26jobs; autenticación no acreditada por esta auditoría; hash c8… previo no comparado con PBS
/home/monxas/appdata/prometheus/alerts.yml Fuente versionada87reglas; versión actual en PBS no comprobada
appdata/alertmanager/{alertmanager.yml,telegram-bot-token,vera-alert-secret} YAML candidato Git; contenido runtime y secretos no verificados; tres mounts RO
appdata/blackbox/blackbox.yml, appdata/loki-config/loki-config.yaml Paths observados; no fuente completa actual localizada; ausencia Git no demuestra ausencia PBS
Datos appdata/{alertmanager/data,grafana,healthchecks,loki,prometheus/data,pushgateway,scrutiny/config,scrutiny/influxdb,uptime-kuma} Nueve binds de datos; JSON Grafana parciales no equivalen a sus bases; sin prueba de consistencia/restore
Named/anonymous volumes Cero named volumes declarados; no descarta image-declared VOLUME, anónimos ni Docker data-root separado: no se inspeccionó Mounts

appdata/… abrevia /home/monxas/appdata/…. RepoDigests observados no sustituyen backups de datos ni acreditan disponibilidad de registry. El perfil conserva complete_recovery_spec: false.

Huecos concretos y propuesta mínima

  • backup-retention.md conserva targets verificados en agosto, anteriores a217. La lectura actual sí acredita su selección: no interpretar la tabla antigua como ausencia de backup ni como inventario actual completo.
  • backup-appdata-fixed.sh, líneas28–39, pertenece a VM208; horario retirado el8sept. No declara una copia diaria de /opt/observa ni del appdata trasladado. No se propone reactivarlo.
  • pbs_restore_drill.py, líneas42–44, permite LXC100/123/155/200/251 y config123: excluye217. El drill19oct probó123. No se encontró prueba de restore217; no añadirlo sin más al pool aleatorio con su pila de diez servicios.
  • normalidad comprueba jobs y frescura, no mounts/payload/coherencia. El éxito agregado no cierra esos huecos.

En esta fase inicial sólo se acreditaron job declarado y snapshot listado, separados de paths comprobados y restore probado. La observación posterior de las 07:16 añade metadatos de las rutas actuales; no acredita payload ni restauración. Antes de un ensayo futuro siguen pendientes volúmenes Docker no representados, exclusiones del snapshot y extracción/restore aislado con límites revisados. No requiere otro daemon, cron o backup.

Evidencia privada y cierre

Archivos0600, fsync de archivo/directorio, sólo metadata filtrada:

  • ~/.local/state/homelab-incident-evidence/ct217-backup-metadata-20261020T004541Z.json, SHA256 <REDACTED>.
  • ~/.local/state/homelab-incident-evidence/ct217-pbs-snapshots-20261020T004641Z.json, SHA256 <REDACTED>.

Las cuatro llamadas de la fase inicial terminaron rc0. En aquella fase no hubo más SSH/PVE tras snapshots, ni cambios en código, perfiles, jobs o almacenamiento.

Observación posterior de los 16 binds de las 07:16 CEST

El 20 de octubre, 07:16:46,037910–07:16:47,313624 CEST, una única SSH agregada por pmx2 revalidó mediante API CT217 en marcha en proxmox2 y proyectó sólo rootfs/mpN: zfs-ha:subvol-217-disk-0,size=40G, ningún mpN. Dentro del guest se consultaron metadatos de las 16 rutas de origen ya enumeradas en el perfil, además del montaje raíz.

  • Las 16 rutas existen: 7 archivos regulares y 9 directorios, sin symlink en el último componente de esas rutas.
  • Findmnt de cada ruta muestra montaje /, ZFS y dispositivo 0:54, iguales al rootfs.
  • Mountinfo consumido en RAM y filtrado bajo esas 16 rutas: 0 submontajes internos observados. No hubo recorrido de archivos, lectura de datos, secretos o bases de datos ni inspect, entorno, Compose o llamadas a aplicaciones.
  • La clave nueva bind_rootfs_metadata_observation del perfil canónico conserva ruta de origen, tipo, propietario, modo, dispositivo y procedencia. No sustituye las capturas históricas ni modifica complete_recovery_spec: false.

Estos metadatos actuales no revelan un hueco externo de cobertura por esos binds. No prueban que el snapshot de las 01:02 contenga esas rutas, sus datos o sus permisos, ni sus exclusiones o la consistencia de las bases de datos. Ninguna de las 16 rutas es un socket, dispositivo o proc/sys; no incluir esos recursos o dependencias externas como si fueran datos respaldados. La cobertura declarada del rootfs y un snapshot listado siguen separados de una restauración verificada.

Los propietarios difieren: Healthchecks 999:999, Kuma 0:0, varios datos 1000:1000 y configuración de Prometheus 0:0. El modo 0777 del directorio Pushgateway es un hecho observado; no se cambió ni se declaró una vulnerabilidad por ese dato aislado. No normalizar propietarios con chown recursivo. El checklist existente de restore apagado debe comparar cada archivo con la versión de su snapshot, no con las 89 reglas actuales. No se restauró ni arrancó un guest o servicio en esta comprobación.

Revisión de fuente: namespace e identidad antes de comparar propietarios

La inspección apagada del checklist debe distinguir los UID/GID observados dentro del guest de los que expone su filesystem montado desde el host. Antes de comparar owners, acreditar el modo y el mapa del snapshot y del destino; no resolver diferencias con chown recursivo. El perfil de CT217 no acredita aquí su modo ni un mapa personalizado: esta revisión no afirma que los use.

Se comprobó una brecha del motor genérico: isolate retiraba lxc.idmap como cualquier otra opción lxc.* antes de arrancar. Una fixture local del flujo completo aceptaba ese caso y terminaba bien, sin conservar la necesidad de revisión. El candidato añade una lectura previa pvesm extractconfig de la copia LXC y la misma guarda antes de modificar la configuración restaurada y durante su prueba de propiedad para limpieza. Rechaza mapas personalizados, includes, valores malformados y duplicados. Antes de admitir el modo por defecto, exige una configuración LXC con un único rootfs no vacío: salida vacía, comentarios, configuración VM o rootfs ausente/duplicado/vacío fallan antes de restore. No exige al volumen original el prefijo del VMID temporal. La configuración se consume sólo en RAM; el recibo privado conserva su SHA y el modo de origen, distinguiendo valor explícito de default, además de la política exigida al destino. No imprime su contenido.

Esto no debe bloquear la conversión soportada de privilegiado a no privilegiado:

  • La definición oficial de configuración declara el default unprivileged=0. Se admiten origen explícito 0 o 1, o ausencia de esa opción con ese significado; no se aceptan valores ambiguos.
  • La API de restore aplica el --unprivileged 1 solicitado al destino; sólo hereda el modo del backup cuando no hay override. También puede recuperar mapas LXC originales, razón para rechazarlos antes de restaurar en este ensayo conservador.
  • La extracción PBS usa el namespace de la configuración de destino. Sin mapa personalizado, Proxmox define el mapa no privilegiado predeterminado. El candidato sigue exigiendo destino explícito 1 sin mapas/includes antes de editar, etiquetar, arrancar o limpiar; no cambia owners a mano.

La consulta de estas fuentes oficiales describe el mecanismo, no una prueba de conversión en los nodos instalados ni la funcionalidad posterior de aplicaciones. Si el error aparece antes de restore, no se crean recursos del guest; si aparece después, se conserva su configuración sin sanitizar ni etiquetar y se retiene la reserva para revisión, sin stop/destroy automático.

Validación exclusivamente local: 62 pruebas, incluidos origen privilegiado explícito/default con restore solicitado a modo 1, rechazo de destino aún privilegiado, mapas/includes y drift durante limpieza. Pasan con Python 3.12 y 3.14; gramática 3.10 comprobada. Los dobles bloquean PVE real; no se ejecutó SSH, restore, backup, arranque o cambio de configuración runtime. Esto no certifica el mapa global del host, el contenido de CT217 ni una recuperación completa.

Helper PBS instalado y verificado el20oct13:34–13:37 CEST

La fuente de las guardas anteriores está en main. A13:34:22 se reemplazó /usr/local/bin/pbs_restore_drill.py en proxmox bajo comprobación de identidad y lock del archivo existente; se preservó root:root0755. Respaldo privado: /root/rollback-pbs-identity-20261020-76l5v4jd. En proxmox2 el instalador encontró ya el candidato exacto y terminó already_current, sin escribir ni crear nuevo backup. No se atribuye esa convergencia a Ansible-pull sin recibo que lo pruebe.

La lectura independiente13:37:53–54 confirma ambos helpers con SHA256 <REDACTED>, 19849bytes, un enlace, root:root0755, y compilación nativa con Python3.13.5. Cero procesos conocidos de drill, cero cmdlines ilegibles, reserva ausente y VMID9901/9902 ausentes tanto en la API como en los archivos de configuración. No se importó ni ejecutó el helper, tampoco help, restore, start, stop o destroy.

Las62pruebas acreditan el comportamiento de fuente; la instalación y compilación no acreditan una conversión real de UID/GID ni recuperación funcional de CT217. La retención vigente se reconcilió aparte con metadatos fechados: políticas PBS y límites. Recuperación del helper de proxmox requiere comprobar candidato y backup antes de reemplazar preservando dueño/modo; no revertir reservas ni recursos de ensayo como parte de ese cambio.