El cifrado de ZFS es una de esas funcionalidades raras que realmente hace el día del ingeniero de almacenamiento mejor: los datos se cifran en disco, las claves se gestionan a nivel de dataset y la replicación puede ocurrir sin convertir tu sitio de DR en un servicio de depósito de claves. El truco mágico detrás de esa última parte es raw send: una forma de replicar los bytes cifrados tal cual, de modo que el destino pueda almacenar y servir el dataset sin llegar a conocer las claves de cifrado.
Esto no es una historia teórica de “libro blanco” sobre seguridad. Raw send es cómo construyes backups multi-sitio sensatos cuando requisitos legales, cumplimiento o el sentido común dicen “el proveedor de backup no debe tener claves”. También es la forma de evitar el error clásico de descifrar en el origen solo para enviar texto plano a un lugar “seguro”. Spoiler: ese lugar “seguro” termina siendo “un lugar con un portátil de administrador comprometido”.
Qué es realmente raw send (y qué no es)
Seamos precisos, porque las discusiones sobre replicación ZFS tienden a colapsar en afirmaciones vagas como “está cifrado, así que es seguro”. Raw send no es “usa ssh y ya está cifrado”. Raw send no es “envía un dataset que por casualidad está cifrado”. Raw send es un modo específico de zfs send donde el stream contiene los bloques y metadatos cifrados tal como están en disco, en lugar de que ZFS los descifre para el stream.
En términos prácticos:
- El envío normal de un dataset cifrado generalmente produce un stream de datos descifrados (a menos que le indiques a ZFS lo contrario). El receptor reconstruye el contenido del dataset, pero el stream en sí no es el ciphertext que residía en disco.
- Raw send produce un stream que mantiene el dataset cifrado de extremo a extremo tal como ZFS lo almacena. El receptor lo guarda cifrado y puede replicarlo más adelante, tomar snapshots, etc.—sin poder montarlo/leerlo a menos que posteriormente se le proporcione la clave.
Resumen en una frase: raw send replica el ciphertext y el contexto de cifrado, no el texto plano.
Dos consecuencias operativas relevantes:
- Con raw send, tu sitio de DR puede ser una “bóveda tonta” para datasets cifrados. Puedes confiarles almacenamiento y replicación sin entregarles las claves.
- Con raw send, el lado receptor aún puede realizar operaciones ZFS (snapshots, holds, replicación adicional), pero no puede “arreglar” tus datos restaurándolos a legibilidad si pierdes las claves. El cifrado es un gran maestro: califica con severidad.
Chiste #1 (breve y relevante): El cifrado es como el cinturón de seguridad: se siente restrictivo hasta que ves a alguien intentar “agarrarse” durante un accidente.
Hechos y contexto histórico
La ingeniería de almacenamiento está llena de energía tipo “lo inventamos en 2005 y seguimos explicándolo en 2025”. Aquí tienes algunos hechos concretos y contexto que hacen que raw send tenga sentido:
- zfs send/receive precede al cifrado nativo de ZFS. La replicación existía mucho antes de que el cifrado fuera parte del diseño principal, así que el modelo de replicación tuvo que ampliarse con cuidado sin romper supuestos previos.
- El cifrado de ZFS es nativo por dataset y a nivel de bloque. No es la historia de un sistema de ficheros sobre LUKS. ZFS cifra bloques y guarda la metadata de cifrado con el dataset, permitiendo claves por dataset y rotación de claves.
- Raw send existe porque “dataset cifrado” no implica automáticamente “stream de replicación cifrado”. Sin el modo raw, ZFS puede enviar una representación lógica del dataset que en la práctica es texto plano en el stream.
- Los snapshots son la unidad de replicación. ZFS send no es “sincroniza la carpeta”. Es “envía la diferencia entre dos puntos en el tiempo”. Por eso tu política de snapshots es tu política de replicación.
- Los tokens de reanudación cambiaron la historia operativa. En enlaces inestables, “empezar de nuevo” solía ser la opción por defecto. Los resume tokens permiten continuar un receive sin reenviar todo.
- Raw send preserva la raíz de cifrado y las propiedades. El límite de cifrado importa: los datasets pueden heredar cifrado, pero raw send necesita el contexto completo de cifrado para mantener la consistencia entre sitios.
- Dedup y compresión no son regalos gratis. Especialmente con cifrado en juego, las expectativas sobre la eficacia de dedup a menudo chocan con la realidad (y con requisitos de RAM).
- Los streams ZFS pueden incluir datos embebidos, bloques grandes y comportamiento de recordsize. Si estás acostumbrado a herramientas a nivel de fichero, el momento de “¿por qué es 3x más grande esto?” llega rápido cuando recordsize, compresión y churn de snapshots interactúan.
Modelo de amenazas: qué protege raw send (y qué no)
Raw send es una herramienta de seguridad, no una manta que lo cubre todo. Úsala para resolver el problema correcto.
Qué protege raw send
- Los administradores del almacenamiento en el destino no pueden leer datos sin las claves. Pueden replicarlos, hacer snapshots, destruirlos o perderlos—pero no pueden explorarlos.
- Los sistemas intermedios no pueden leer el contenido del stream si el stream raw se transporta sobre infraestructura no confiable. (Aún pueden manipularlo, lo cual es otra conversación.)
- Separación de claves entre entornos. Puedes mantener las claves de producción en producción y aun así mantener copias fuera de sitio de los datasets cifrados.
Qué no protege raw send
- Integridad por sí sola. Raw send garantiza confidencialidad, no autenticidad. Los checksums de ZFS ayudan a detectar corrupción, pero todavía debes pensar en integridad de transporte, errores de disco y modificaciones hostiles.
- Disponibilidad. Si pierdes las claves, tu sitio de DR se convierte en una exhibición de museo titulada “Bloques cifrados, época: el martes pasado”.
- Fugas de metadata más allá de lo que cubre el cifrado. Dependiendo de la implementación y propiedades, cierta metadata (nombres de dataset, nombres de snapshots, tamaños, tiempos) puede ser observable a través de propiedades ZFS y logs operativos.
- Higiene deficiente de snapshots. Si haces snapshots y replicas secretos que no deberías haber guardado, raw send fielmente enviará tu error fuera de sitio.
Modelo mental: cifrado y flujos de send que necesitas
El modelo mental más útil es este: ZFS tiene dos formas amplias de representar un dataset para replicación.
- Representación lógica: “Aquí están los ficheros/bloques como deberían aparecer.” ZFS puede reconstruir desde esto y escribir bloques en el receptor. Aquí es donde el texto plano puede aparecer en el stream incluso si los datos en disco están cifrados—porque ZFS está describiendo el contenido lógico.
- Representación raw: “Aquí están los bloques exactos en disco y la metadata.” Si el dataset está cifrado, esos bloques son ciphertext. El receptor los almacena como ciphertext. No se requieren claves para almacenarlos; sí para interpretarlos.
Raw send también interactúa con el concepto de una encryption root. En ZFS, un dataset puede heredar cifrado de un padre. La encryption root es donde se establecen los parámetros de cifrado. Al replicar, necesitas preservar el límite de cifrado, o acabarás con un destino que no puede representar correctamente la herencia de claves y propiedades.
Aquí es donde la gente tropieza: asumen que “dataset cifrado” implica “el receptor podrá cargar la clave y montarlo”. Eso puede ser cierto, pero es opcional. Raw send está diseñado explícitamente para que el receptor no necesite claves para recibir. Si luego puede montarlo depende de si cargas la clave en destino y de que los parámetros de cifrado coincidan con lo esperado.
Chiste #2 (breve y relevante): En almacenamiento, “funcionó en staging” es solo una forma educada de decir “producción tiene más entropía”.
Tareas prácticas: comandos que ejecutarás en producción
A continuación hay tareas reales que harás al construir y operar replicación raw send. Cada tarea incluye comandos y qué observar. Asumo herramientas estilo OpenZFS en Linux, pero los conceptos se traducen a otras plataformas con pequeñas diferencias en flags.
Tarea 1: Confirmar que el dataset está cifrado e identificar la encryption root
cr0x@source:~$ zfs get -H -o name,property,value encryption,keylocation,keystatus,encryptionroot tank/prod
tank/prod encryption aes-256-gcm
tank/prod keylocation prompt
tank/prod keystatus available
tank/prod encryptionroot tank/prod
Interpretación: Si encryption=off, raw send no va a cifrar mágicamente nada. Si encryptionroot es un dataset padre, ten en cuenta que podrías estar replicando un árbol donde los hijos heredan claves.
Tarea 2: Crear un snapshot de replicación con una convención de nombres que no cause problemas después
cr0x@source:~$ zfs snapshot -r tank/prod@rep-2025-12-25T0200Z
cr0x@source:~$ zfs list -t snapshot -o name,used,creation -r tank/prod | tail -5
tank/prod@rep-2025-12-25T0200Z 0B Thu Dec 25 02:00 2025
tank/prod/db@rep-2025-12-25T0200Z 0B Thu Dec 25 02:00 2025
tank/prod/app@rep-2025-12-25T0200Z 0B Thu Dec 25 02:00 2025
Interpretación: Los nombres de snapshot se convierten en manejadores operativos. Si tu nomenclatura es inconsistente, tus scripts de replicación incremental acabarán encantados por fantasmas.
Tarea 3: Hacer un send raw completo a un dataset nuevo en el destino (sin montar)
cr0x@source:~$ zfs send -w -R tank/prod@rep-2025-12-25T0200Z | ssh cr0x@dest "zfs receive -uF backup/prod"
cr0x@dest:~$ zfs list -o name,used,avail,keystatus,mounted backup/prod
NAME USED AVAIL KEYSTATUS MOUNTED
backup/prod 112G 38.2T unavailable no
Interpretación: -w es el switch de raw send. -R replica el dataset y sus descendientes más propiedades. En el receptor, -u lo deja sin montar (buena práctica cuando no están presentes las claves). Ver keystatus=unavailable en el destino es el objetivo: recibió datos cifrados sin claves.
Tarea 4: Verificar que realmente recibiste un dataset cifrado (no texto plano)
cr0x@dest:~$ zfs get -H -o name,property,value encryption,keystatus,encryptionroot backup/prod
backup/prod encryption aes-256-gcm
backup/prod keystatus unavailable
backup/prod encryptionroot backup/prod
Interpretación: Si encryption aparece como off aquí, no hiciste lo que creías haber hecho. Detente e investiga antes de replicar más.
Tarea 5: Realizar un send incremental raw (el caballo de batalla)
cr0x@source:~$ zfs snapshot -r tank/prod@rep-2025-12-25T0300Z
cr0x@source:~$ zfs send -w -R -I tank/prod@rep-2025-12-25T0200Z tank/prod@rep-2025-12-25T0300Z | ssh cr0x@dest "zfs receive -uF backup/prod"
cr0x@dest:~$ zfs list -t snapshot -o name,creation -r backup/prod | tail -3
backup/prod@rep-2025-12-25T0200Z Thu Dec 25 02:00 2025
backup/prod@rep-2025-12-25T0300Z Thu Dec 25 03:00 2025
Interpretación: -I envía todos los snapshots intermedios entre dos puntos (útil cuando podrías haberte saltado algunos). Si tu grafo de snapshots está limpio, -i es más ajustado. Para simplicidad operativa, -I suele ganar.
Tarea 6: Estimar el tamaño del send antes de saturar un enlace (o ventana de cambios)
cr0x@source:~$ zfs send -nP -w -R -I tank/prod@rep-2025-12-25T0200Z tank/prod@rep-2025-12-25T0300Z
size 21474836480
incremental size 21474836480
Interpretación: -nP es una ejecución en seco con salida parseable. Ese “size” es tu número para planificar. Si es mucho mayor de lo esperado, probablemente tienes churn de snapshots, mismatch de recordsize o una aplicación que “reescribe el fichero completo cada minuto”.
Tarea 7: Recibir en un área de contención segura usando -u y verificar que nada se monta automáticamente
cr0x@dest:~$ zfs receive -uF backup/prod < /dev/null
cannot receive: failed to read from stream
Interpretación: El comando falla porque no hay stream, pero el punto es cultural: siempre incluye -u en la automatización para copias DR cifradas a menos que explícitamente estés ejecutando un warm standby con claves cargadas.
Tarea 8: Usar resume tokens para sobrevivir enlaces inestables
cr0x@dest:~$ zfs get -H -o value receive_resume_token backup/prod
1-8f9c2f1d7c-100000-7890abcdef-200000-10
Interpretación: Si un receive fue interrumpido, esta propiedad puede contener un token. No es un trofeo; es tu salida de emergencia.
cr0x@source:~$ ssh cr0x@dest "zfs get -H -o value receive_resume_token backup/prod"
1-8f9c2f1d7c-100000-7890abcdef-200000-10
cr0x@source:~$ zfs send -w -t 1-8f9c2f1d7c-100000-7890abcdef-200000-10 | ssh cr0x@dest "zfs receive -uF backup/prod"
Interpretación: zfs send -t reanuda desde el token. Esto puede ahorrarte horas (y la relación con el equipo de red).
Tarea 9: Confirmar que el destino no puede montar sin claves (comportamiento esperado)
cr0x@dest:~$ zfs mount backup/prod
cannot mount 'backup/prod': encryption key not loaded
Interpretación: Esto es una condición de éxito para el “modo bóveda”. Si esperabas montar, necesitas un plan de gestión de claves, no un flag distinto de ZFS.
Tarea 10: Cargar una clave en el destino (solo cuando corresponda)
cr0x@dest:~$ zfs load-key backup/prod
Enter passphrase for 'backup/prod':
cr0x@dest:~$ zfs get -H -o value keystatus backup/prod
available
cr0x@dest:~$ zfs mount backup/prod
cr0x@dest:~$ zfs get -H -o value mounted backup/prod
yes
Interpretación: Has cruzado la línea de “DR solo almacenamiento” a “DR con capacidad de lectura”. Aquí es donde los equipos de auditoría empiezan a preguntar quién puede escribir esa passphrase y dónde se guarda.
Tarea 11: Validar el estado de replicación comparando listas de snapshots
cr0x@source:~$ zfs list -t snapshot -o name -r tank/prod | grep '@rep-' | tail -5
tank/prod@rep-2025-12-25T0200Z
tank/prod@rep-2025-12-25T0300Z
tank/prod@rep-2025-12-25T0400Z
tank/prod@rep-2025-12-25T0500Z
tank/prod@rep-2025-12-25T0600Z
cr0x@dest:~$ zfs list -t snapshot -o name -r backup/prod | grep '@rep-' | tail -5
backup/prod@rep-2025-12-25T0200Z
backup/prod@rep-2025-12-25T0300Z
backup/prod@rep-2025-12-25T0400Z
backup/prod@rep-2025-12-25T0500Z
backup/prod@rep-2025-12-25T0600Z
Interpretación: La corrección de la replicación empieza por “¿tenemos los mismos endpoints de snapshot?” No lo compliques en exceso.
Tarea 12: Usar holds para prevenir la eliminación de snapshots durante la replicación
cr0x@source:~$ zfs hold -r keepforrep tank/prod@rep-2025-12-25T0600Z
cr0x@source:~$ zfs holds -r tank/prod@rep-2025-12-25T0600Z | head
NAME TAG TIMESTAMP
tank/prod@rep-2025-12-25T0600Z keepforrep Thu Dec 25 06:01 2025
Interpretación: Los holds están infravalorados. Evitan que trabajos de limpieza bienintencionados borren el snapshot del que depende tu cadena incremental.
Tarea 13: Comprobar throughput de send/receive e identificar dónde se consume tiempo
cr0x@source:~$ zpool iostat -v 2
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 9.21T 5.32T 210 980 185M 612M
raidz2-0 9.21T 5.32T 210 980 185M 612M
sda - - 26 120 23.1M 76.4M
sdb - - 25 122 22.9M 77.1M
...
Interpretación: Si el ancho de banda de escritura en disco es alto pero tu red es baja, podrías estar limitado por CPU (cifrado/compresión), la elección del cipher de ssh o escrituras sincronizadas del receptor. Si la lectura de disco es baja, el send podría no estar tirando tanto como esperabas (o bloqueado en otro lado).
Tarea 14: Recibir con seguridad cuando el destino ya tiene datos (forzar rollback con cuidado)
cr0x@dest:~$ zfs receive -uF backup/prod
cannot receive: failed to read from stream
Interpretación: La parte importante es el flag: -F fuerza un rollback del dataset destino al snapshot más reciente que coincida con el stream. Es poderoso y puede destruir snapshots locales más nuevos. Úsalo solo cuando el destino sea estrictamente un objetivo de replicación, no un lugar donde la gente haga trabajo local.
Tarea 15: Verificar que la clave de cifrado no fue copiada accidentalmente en la automatización
cr0x@dest:~$ zfs get -H -o name,property,value keylocation backup/prod
backup/prod keylocation none
Interpretación: Para el “modo bóveda”, keylocation=none (o una fuente no automática) reduce la posibilidad de que claves se carguen silenciosamente al reiniciar. Si tu entorno espera auto-load, documéntalo y audítalo.
Tres mini-historias del mundo corporativo
1) Incidente causado por una suposición errónea: “dataset cifrado” equivale a “replicación cifrada”
En una gran organización (de las que tienen tres sistemas de tickets y cero calendarios compartidos), un equipo movió un dataset sensible a ZFS encryption y declaró victoria. Cumplimiento gustó de las palabras “AES-256”, liderazgo gustó de que nadie pidió presupuesto y el equipo de almacenamiento gustó de no tener que enseñar a desarrolladores sobre gestión de secretos.
Luego vino la replicación DR. Alguien montó zfs send y zfs receive con prisa, porque el sistema de backup antiguo estaba al final de su vida y el proveedor había empezado a hablar solo de cotizaciones de renovación. La replicación funcionó, los snapshots aparecieron en el sitio remoto y todos volvieron a sus tareas.
Meses después, durante una revisión de seguridad, un auditor hizo una pregunta simple: “¿Pueden los administradores en el sitio remoto leer los datos replicados?” La respuesta debía ser “no”. El resultado de la prueba fue “sí”, y fue incómodo exactamente como te lo imaginas—callado, profesional y con muchas notas.
El postmortem no fue sobre mala intención. Fue sobre una suposición: el equipo pensó que cifrado en disco implicaba cifrado en vuelo y en el stream. Pero su replicación estaba enviando un stream no-raw, y el receptor almacenaba un dataset que podía montarse localmente sin la frontera de cifrado original. Habían construido DR que lucía correcto en el monitoreo pero violaba el requisito de seguridad central.
La solución fue directa: reconstruir la replicación usando raw send, verificar el keystatus=unavailable en destino y escribir un runbook que forzara una decisión explícita: “¿Estamos construyendo una bóveda o un warm standby?” La lección fue la que siempre reaprendemos: en ZFS, una propiedad de dataset no es política a menos que la pruebes end-to-end.
2) Optimización que salió mal: “Activemos dedup para los backups”
En otro lugar, con otra buena intención. Tenían snapshots nocturnos de imágenes de VM y volúmenes de bases de datos. La replicación al sitio DR consumía ancho de banda y buscaban reducirlo. Alguien sugirió dedup: “Tenemos muchos bloques similares; dedup de ZFS lo triturará.” La idea sonó plausible y la frase “tritura ancho de banda” tiene cierta musicalidad.
Activaron dedup en el pool destino, razonando que “son solo backups”. Durante un tiempo vieron mejora en uso de espacio y deltas algo más pequeños. Luego el sistema empezó a sentirse lento. Al principio parecía jitter de red. Luego latencia de disco. Finalmente pareció todo: receives lentos, snapshots lentos y paradas ocasionales que hicieron sospechar la capa del hipervisor.
El retroceso fue predecible en retrospectiva: dedup necesita memoria para la DDT (dedup table), y los bloques cifrados raw no hacen dedup como la gente intuitivamente espera. El cifrado tiende a convertir “bloques de texto plano similares” en “ciphertext con aspecto aleatorio”, así que la ganancia de dedup puede ser pequeña mientras el coste de DDT es real. Habían cambiado ancho de banda por complejidad persistente y un nuevo modo de fallo.
Revirtieron dedup, aceptaron que compresión y frecuencia sensata de snapshots eran mejores herramientas y añadieron una métrica: “coste de replicación por GB cambiado”. Moraleja: si una optimización altera el perfil de memoria y metadata de tu almacenamiento, no optimizaste—cambiaste el sistema. A veces está bien, pero nunca es “gratis”.
3) Una práctica aburrida pero correcta que salvó el día: holds de snapshots y disciplina en la cadena
Los incidentes más heroicos suelen ser los menos glamurosos. Un equipo corría snapshots horarios e incrementales raw a un sitio remoto. También tenían una regla dolorosamente aburrida: los snapshots de replicación recibían un tag de hold, y los trabajos de limpieza estaban prohibidos de eliminar snapshots con hold. No era ingenioso. No impresionó a nadie en reuniones de arquitectura. Era simplemente… política.
Entonces llegó un cambio: un equipo de aplicación desplegó una nueva versión que generó churn masivo—reescribiendo ficheros grandes en vez de hacer append. Los deltas de replicación se dispararon, el enlace se saturó y el job de replicación se retrasó. Mientras tanto, el job de limpieza en el origen estaba felizmente borrando snapshots antiguos porque “solo guardamos 48 horas”.
Excepto que no pudo borrar los snapshots ancla de replicación, porque tenían hold. Eso significó que la cadena incremental se mantuvo intacta mientras el equipo de operaciones limitaba carga, ajustaba la frecuencia de snapshots y daba tiempo a la replicación para ponerse al día. Sin holds, habrían perdido el snapshot base a mitad de proceso y habrían tenido que hacer un resync completo en el peor momento.
Cuando todo se calmó, el postmortem no señaló villanos. El sistema de replicación sobrevivió gracias a una práctica que nadie quería destacar: convenciones de nombres, holds y negarse a ser ingeniosos. En producción, lo aburrido es una característica.
Guía rápida de diagnóstico
Cuando la replicación raw send es lenta, falla o se comporta de forma extraña, no necesitas una lista de 40 pasos primero. Necesitas un embudo rápido que identifique la categoría del cuello de botella: CPU, disco, red o semántica ZFS (snapshots/streams/propiedades). Este es el playbook que uso antes de dejar que alguien empiece a “tunear”.
Primero: confirma qué estás haciendo realmente (raw vs no-raw, full vs incremental)
cr0x@source:~$ zfs send -nP -w -R -I tank/prod@rep-2025-12-25T0200Z tank/prod@rep-2025-12-25T0300Z
size 21474836480
incremental size 21474836480
Mira: si el size es mucho mayor de lo esperado, el “cuello de botella” suele ser “estás enviando más de lo que crees” por churn o selección de snapshots.
Segundo: revisa restricciones en el receptor (espacio, readonly, estado incompatible del dataset)
cr0x@dest:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
backup 40T 28.1T 11.9T - - 21% 70% 1.00x ONLINE -
cr0x@dest:~$ zfs get -H -o name,property,value readonly,available,receive_resume_token backup/prod
backup/prod readonly off
backup/prod available 11.2T
backup/prod receive_resume_token -
Mira: poco espacio libre, readonly=on o un resume token que indique interrupciones repetidas.
Tercero: decide si el cuello de botella es disco, CPU o red
Disco:
cr0x@source:~$ zpool iostat -v 2
cr0x@dest:~$ zpool iostat -v 2
Mira: alta latencia/await (en plataformas que lo muestran), saturación de un vdev único o escrituras receptoras al máximo mientras la CPU está inactiva.
CPU / cripto:
cr0x@source:~$ top -b -n 1 | head -20
cr0x@dest:~$ top -b -n 1 | head -20
Mira: un core pegado por ssh o crypto del kernel, indicando elección de cipher o falta de aceleración hardware.
Red:
cr0x@source:~$ ip -s link show dev eth0
cr0x@dest:~$ ip -s link show dev eth0
Mira: errores/paquetes perdidos. Si el enlace está limpio pero el throughput es bajo, sospecha de una etapa monohilo (cipher de ssh, buffer de userland o comportamiento sync del receptor).
Cuarto: inspecciona comportamiento de zfs receive y compatibilidad del stream
cr0x@dest:~$ zfs events -v | tail -30
Mira: eventos sobre receives fallidos, errores de checksum o fallos a nivel de pool que hacen que la replicación “vaya lenta” porque está reintentando constantemente.
Errores comunes, síntomas, soluciones
Error 1: Olvidar raw mode y asumir que el cifrado se transmite
Síntoma: el dataset destino se puede montar/leer sin cargar la clave esperada; o destino encryption=off.
Solución: reconstruye la replicación con raw send y verifica en el destino:
cr0x@source:~$ zfs send -w -R tank/prod@rep-2025-12-25T0200Z | ssh cr0x@dest "zfs receive -uF backup/prod"
cr0x@dest:~$ zfs get -H -o name,property,value encryption,keystatus backup/prod
backup/prod encryption aes-256-gcm
backup/prod keystatus unavailable
Error 2: Romper cadenas incrementales borrando snapshots
Síntoma: cannot send '...': incremental source ... does not exist o el receptor rechaza el stream por base faltante.
Solución: añade holds a snapshots ancla y solo podar snapshots confirmados como replicados.
cr0x@source:~$ zfs hold -r keepforrep tank/prod@rep-2025-12-25T0600Z
cr0x@source:~$ zfs release -r keepforrep tank/prod@rep-2025-12-25T0200Z
Error 3: Usar -F a ciegas en un destino que no es “solo replicación”
Síntoma: pérdida “misteriosa” de snapshots locales o cambios en el destino después de correr la replicación.
Solución: separa datasets: uno estrictamente para replicación y otro para uso local. O elimina -F y maneja divergencias explícitamente.
Error 4: Permitir que el destino auto-monte datasets cifrados
Síntoma: montajes inesperados al arranque, claves cargadas “de alguna manera”, mayor radio de impacto si una cuenta de administrador DR es comprometida.
Solución: recibir con -u, establecer keylocation controlado y auditar procedimientos de carga de claves.
cr0x@dest:~$ zfs set canmount=off backup/prod
cr0x@dest:~$ zfs get -H -o name,property,value canmount,mounted backup/prod
backup/prod canmount off
backup/prod mounted no
Error 5: Confundir “transporte cifrado” con “confidencialidad de raw send”
Síntoma: revisión de seguridad indica que los backups son descifrables en destino, o que sistemas intermedios podrían ver texto plano.
Solución: trata ssh/TLS como protección de transporte; trata raw send como protección del formato de datos. Usa ambos cuando necesites defensa en profundidad.
Error 6: “Tuning” de rendimiento añadiendo capas (y latencia)
Síntoma: replicación más lenta tras introducir compresión extra, cifrado adicional o defaults de buffering pesados.
Solución: mide cada etapa; simplifica el pipeline; confirma balance CPU-disco. Si añades una herramienta, debes justificarla con métricas.
Listas de verificación / plan paso a paso
Plan A: Construir una réplica DR estilo bóveda (el destino no puede leer datos)
- En origen, confirma que el cifrado está habilitado y toma nota de la encryption root.
- Crea un snapshot de replicación recursivo con un esquema de nombres estable.
- Haz una estimación en seco del tamaño para el envío inicial completo.
- Realiza un raw send completo con
-w -R. - Recibe con
-uy consideracanmount=offen el destino. - Verifica
keystatus=unavailableen destino y que el dataset permanezca sin montar. - Automatiza sends incrementales raw horarios/diarios con holds en snapshots.
- Define reglas de poda que respeten los holds y verifica que los snapshots estén replicados antes de eliminar.
Plan B: Construir un warm standby (el destino puede montar con claves controladas)
- Haz todo lo del Plan A inicialmente.
- Define manejo de claves: quién carga claves, dónde viven las passphrases, cómo se audita.
- Prueba carga manual de clave y montaje en una ventana de mantenimiento controlada.
- Decide si las claves deben cargarse automáticamente al arranque (la mayoría debería decir “no” salvo razones operativas fuertes).
- Realiza un ensayo de failover: promociona servicios, confirma consistencia de aplicación y mide RTO.
Paso a paso: Un bucle mínimo y reproducible de replicación
Esta es la versión “si estás cansado y son las 02:00”. Asume conectividad SSH y que el destino es una réplica estricta.
cr0x@source:~$ export SRC=tank/prod
cr0x@source:~$ export DST=backup/prod
cr0x@source:~$ export SNAP=rep-$(date -u +%Y-%m-%dT%H%MZ)
cr0x@source:~$ zfs snapshot -r ${SRC}@${SNAP}
cr0x@source:~$ zfs hold -r keepforrep ${SRC}@${SNAP}
cr0x@source:~$ LAST=$(zfs list -t snapshot -o name -s creation -r ${SRC} | grep '@rep-' | tail -2 | head -1)
cr0x@source:~$ CURR=${SRC}@${SNAP}
cr0x@source:~$ zfs send -nP -w -R -I ${LAST} ${CURR}
cr0x@source:~$ zfs send -w -R -I ${LAST} ${CURR} | ssh cr0x@dest "zfs receive -uF ${DST}"
Interpretación: Esto crea un nuevo snapshot, lo pone en hold, encuentra el snapshot de replicación anterior, estima tamaño y luego envía incrementalmente en modo raw. En la automatización real, manejarías el caso del “primer envío” y liberarías holds cuando sea seguro.
Preguntas frecuentes (FAQ)
1) ¿Significa raw send que no necesito cifrado SSH?
No. Raw send protege la confidencialidad del payload incluso si es interceptado, pero SSH sigue siendo importante para autenticación, protección contra manipulación en tránsito y para reducir riesgos operativos. Usa raw send para “no hay claves en destino” y SSH para “nadie inserte basura en mi receive”.
2) ¿Puede el destino replicar el dataset cifrado hacia otro lado sin claves?
Sí, esa es una de las mejores partes. El destino puede realizar raw sends del dataset cifrado a otro objetivo, actuando como relé o bóveda secundaria, sin cargar nunca claves.
3) ¿Qué significa realmente keystatus=unavailable?
Significa que ZFS sabe que el dataset está cifrado pero no tiene la clave cargada. El dataset puede existir, replicarse y gestionarse, pero no puede montarse ni leerse.
4) Si pierdo las claves, ¿puedo restaurar desde la réplica raw?
Puedes restaurar la estructura del dataset y los snapshots, pero no puedes descifrar el contenido. La réplica raw no es una solución a la pérdida de claves. Trata las claves como las joyas de la corona: respaldadas, con control de acceso y probadas.
5) ¿Por qué mi send incremental es enorme cuando solo cambió poco?
Causas comunes: una aplicación reescribe ficheros grandes en vez de hacer append, una imagen VM sufre churn de bloques grandes, mismatch de recordsize amplifica cambios o estás enviando un rango de snapshots más amplio del pretendido (ej., -I incluyendo intermedios con mayor churn).
6) ¿Puedo cambiar propiedades en la réplica del destino?
Puedes, pero con cuidado: la replicación con -R tiende a preservar propiedades del origen y receives repetidos pueden revertir cambios en el destino. Si necesitas propiedades distintas en destino (mountpoints, cuotas), planifícalo explícitamente y prueba cómo interactúan tus flags de receive.
7) ¿Cuál es la diferencia entre recibir con -u y fijar canmount=off?
-u evita montar durante la operación de receive. canmount=off es una propiedad persistente que impide montarlo salvo que se cambie. Para réplicas bóveda, a menudo hago ambas: recibir sin montar y mantenerlo así por política.
8) ¿Debo usar -i o -I para incrementales?
-i envía de un snapshot a otro directamente (más preciso, asume cadenas limpias). -I incluye snapshots intermedios entre puntos (más resiliente ante envíos saltados, a veces streams más grandes). En entornos corporativos con jobs fallidos y programación humana, -I suele ser el predeterminado más seguro.
9) ¿Cómo sé que el destino no está recibiendo claves accidentalmente?
Revisa keystatus y keylocation, y audita quién puede ejecutar zfs load-key. También revisa unidades/scripts de arranque para comportamiento de carga de claves. La promesa de “no hay claves” falla con más frecuencia por automatizaciones de conveniencia añadidas después.
10) ¿Raw send es más lento que el send normal?
Depende. Raw send puede ser eficiente porque envía bloques tal como están almacenados, pero el throughput global depende de todo el pipeline: lectura en origen, procesamiento de zfs send, transporte, escrituras del receptor y topología del pool. El predictor de rendimiento más importante suele ser el churn y las características de I/O, no el flag raw en sí.
Conclusión
ZFS raw send es una de esas funciones que habilita silenciosamente infraestructura madura: puedes replicar datasets cifrados a lugares que nunca deberían ver claves, construir cadenas de backup multi-hop y hacerlo con semántica ZFS de primera clase—snapshots, incrementales y streams reanudables.
La disciplina operativa es el verdadero coste: higiene de snapshots, integridad de la cadena, límites de gestión de claves y verificar qué crees que estás replicando. Si haces eso bien, raw send es un regalo. Si lo haces de forma descuidada, o filtrarás datos o descubrirás, en el peor momento, que tus “backups” son pisapapeles criptográficos.