Google Workspace
Backup y restauración cloud-to-cloud de cuentas Google Workspace. Rust puro — un plugin de FD (gworkspace-fd.so) más un binario de backend, sin JVM, sin Python, sin agentes dentro de Google.
Capacidades
Sección titulada «Capacidades»| Carga | Backup | Incremental | Restauración |
|---|---|---|---|
| Gmail | .eml con fidelidad total (RFC822, etiquetas preservadas) | history API | reinserción con etiquetas recreadas |
| Google Drive | binarios nativos + Docs/Sheets/Slides exportados (docx/xlsx/pptx, configurable) | changes API | subida bajo NGBackup Restore <fecha>/ |
| Google Calendar | JSON por evento | recorrido completo | events.import |
| Google Contacts | JSON por contacto | recorrido completo | people:createContact |
Todas las cargas soportan restauración al origen y restauración entre usuarios (restore_user=). La descarga de archivos virtuales al filesystem (where=/path) está actualmente limitada (ver Restauración abajo). Shared Drives, la configuración de Gmail y los tombstones de borrado están en el roadmap.
- Service account + Domain-Wide Delegation (OAuth 2.0, JWT RS256) — una clave protege todo el dominio; impersonación por usuario, sin contraseñas de usuario.
- Nuevos usuarios incluidos automáticamente: los jobs de dominio enumeran los usuarios activos vía Admin SDK Directory API en cada ejecución.
- Formato Gmail compatible con Takeout: cada mensaje es un
.emlindependiente con cabeceraX-Gmail-Labels:— el formato autocontenido se abre en cualquier cliente de correo tras una exportación vía restauración al origen. - Consciente de cuotas: backoff exponencial truncado en 429 / 403 rate-limit / 5xx respetando
Retry-After(modelo de cuota de Gmail: 6.000 unidades/min/usuario). - Higiene de secretos: las claves inline se rechazan al parsear; la clave de la service account vive en un archivo 0600 (
sa_key_file=).
Requisitos
Sección titulada «Requisitos»- Google Cloud Console: crea un proyecto (o reutiliza el proyecto de backup de la organización), habilita las APIs Gmail API, Google Drive API, Google Calendar API, People API y Admin SDK API, crea una service account y descarga su clave JSON.
- Copia el Client ID OAuth2 numérico de la service account (en la página de detalles de la SA).
- Consola de administración de Workspace (admin.google.com): Seguridad → Controles de API → Delegación de todo el dominio → añade el client ID numérico con exactamente estos scopes (la propagación puede tardar hasta 24 h, normalmente minutos):
https://www.googleapis.com/auth/gmail.readonlyhttps://www.googleapis.com/auth/drive.readonlyhttps://www.googleapis.com/auth/calendar.readonlyhttps://www.googleapis.com/auth/contacts.readonlyhttps://www.googleapis.com/auth/admin.directory.user.readonlyhttps://www.googleapis.com/auth/gmail.modifyhttps://www.googleapis.com/auth/drivehttps://www.googleapis.com/auth/calendar.eventshttps://www.googleapis.com/auth/contactsInstalación
Sección titulada «Instalación»Instala el paquete ngbackup-gworkspace-plugin (deb/rpm) en el host cliente que ejecutará los jobs y coloca la clave y la configuración:
install -o bacula -g bacula -m 0600 sa-key.json /opt/ngbackup/etc/gworkspace/sa-key.jsoncp gworkspace.conf.example /opt/ngbackup/etc/gworkspace/gworkspace.conf # edit domain/admin_userComprobación previa (código de salida 0 = todo correcto):
sudo -u bacula gworkspace-backend mode=verify \ config_file=/opt/ngbackup/etc/gworkspace/gworkspace.conf user=someone@yourdomainConfiguración
Sección titulada «Configuración»gworkspace.conf
Sección titulada «gworkspace.conf»Formato key = value; las claves de la línea Plugin = sobrescriben el archivo.
| Clave | Significado |
|---|---|
domain | Dominio primario del Workspace (rutas virtuales y consultas a la Directory API) |
sa_key_file | Clave JSON de la service account con DWD habilitada — modo 0600 |
admin_user | Admin impersonado para la enumeración de usuarios vía Directory API (jobs de dominio y list pluginobjects); innecesario cuando los jobs pasan user= explícito |
working_dir | Directorio de checkpoints (historyId de Gmail / pageToken de Drive), por defecto /opt/ngbackup/working |
log_level | Opcional; debug para ejecuciones verbosas |
page_size | Opcional; tamaño de página de las APIs (p. ej. 500) |
export_docs | Formato de exportación de Docs: docx | odt | pdf | txt | html | md |
export_sheets | Formato de exportación de Sheets: xlsx | ods | pdf | csv | tsv |
export_slides | Formato de exportación de Slides: pptx | odp | pdf | txt |
max_file_mb | Límite por archivo de Drive en MiB, 0 = ilimitado |
include_trash | Respaldar elementos en la papelera (no por defecto) |
Línea Plugin=
Sección titulada «Línea Plugin=»El prefijo gworkspace: enruta al plugin; todo lo que sigue son pares key=value separados por espacios. Valores de mode=: account (los cuatro servicios) | gmail | drive | calendar | contacts | verify. Los jobs de dominio (mode=account sin user=) reenumeran los usuarios activos en cada ejecución — los nuevos empleados quedan protegidos automáticamente.
Enumera los usuarios del dominio desde la consola con líneas Plugin = listas para pegar:
list pluginobjects client=<fd> plugin="gworkspace: config_file=/opt/ngbackup/etc/gworkspace/gworkspace.conf"Ejemplos de FileSet, Schedule y Job
Sección titulada «Ejemplos de FileSet, Schedule y Job»# Whole-domain, all services (Gmail + Drive + Calendar + Contacts).FileSet { Name = "FS-GWorkspace-Domain" Include { Options { Signature = MD5; Compression = GZIP } Plugin = "gworkspace: mode=account \ config_file=/opt/ngbackup/etc/gworkspace/gworkspace.conf" }}
# Gmail only, two explicit users, excluding a label.FileSet { Name = "FS-GWorkspace-Gmail-Pilot" Include { Options { Signature = MD5; Compression = GZIP } Plugin = "gworkspace: mode=gmail \ config_file=/opt/ngbackup/etc/gworkspace/gworkspace.conf \ labels_exclude=Newsletters" }}
# Drive only, PDFs kept native, Google Docs exported as ODT.FileSet { Name = "FS-GWorkspace-Drive" Include { Options { Signature = MD5; Compression = GZIP } Plugin = "gworkspace: mode=drive \ config_file=/opt/ngbackup/etc/gworkspace/gworkspace.conf \ export_docs=odt" }}
# 2x/day: Full weekly + Incremental at 07:00 and 19:00.# Gmail incrementals use history.list, Drive uses changes.list.Schedule { Name = "Sched-GWorkspace-2xDay" Run = Level=Full sun at 01:00 Run = Level=Incremental mon-sat at 07:00 Run = Level=Incremental mon-sat at 19:00}
Job { Name = "BackupGoogleWorkspace" Type = Backup Level = Incremental Client = ngbackup-fd # FD where gworkspace-fd.so is installed FileSet = "FS-GWorkspace-Domain" Schedule = "Sched-GWorkspace-2xDay" Storage = File1 Pool = Default Messages = Standard Accurate = no}Restauración
Sección titulada «Restauración»De vuelta a la misma cuenta (recomendado)
Sección titulada «De vuelta a la misma cuenta (recomendado)»restore en bconsole → marca los elementos → where=/. Los mensajes de Gmail se reinsertan con sus etiquetas (las etiquetas personalizadas ausentes se recrean); los archivos de Drive caen bajo NGBackup Restore <fecha>/ (nunca sobrescribe archivos vivos); los eventos de Calendar se reimportan; los Contacts se recrean.
A otro usuario (empleado que se fue, migración)
Sección titulada «A otro usuario (empleado que se fue, migración)»Añade restore_user=target@domain a la cadena de opciones del plugin en el momento de la restauración. Todos los objetos seleccionados caen en la cuenta de destino (Drive bajo la carpeta de restauración, Gmail con etiquetas, Calendar en primary).
Descarga al filesystem (where=/path) — limitación
Sección titulada «Descarga al filesystem (where=/path) — limitación»Restaurar los archivos virtuales del plugin a una ubicación alternativa del filesystem produce actualmente archivos de 0 bytes: el File Daemon enruta las restauraciones a ubicación alternativa a su extractor interno (core), que no invoca al plugin y no puede materializar un data-stream de plugin como contenido de archivo normal. Es una limitación compartida entre los plugins de archivo virtual de NGBackup, no específica de Google Workspace. Para obtener archivos en disco, restaura al origen (en la cuenta original o en una cuenta temporal) y exporta desde Google. Enrutar las restauraciones where= por el plugin está en el roadmap.
Ver también: Restauración, Instant Recovery & V2V.
Solución de problemas
Sección titulada «Solución de problemas»Logs: /opt/ngbackup/working/gworkspace-backend.log. Checkpoints: /opt/ngbackup/working/gworkspace/<domain>/state.json — borrar el archivo fuerza un resync completo en el próximo Incremental (seguro; nunca borra datos ya respaldados).
| Síntoma | Causa probable | Acción |
|---|---|---|
token exchange HTTP 401 invalid_grant | DWD no autorizada / client ID incorrecto / desfase de reloj | Revisa el paso de delegación; timedatectl con NTP activo |
token exchange HTTP 400 + unauthorized_client | Lista de scopes en la consola admin ≠ scopes solicitados | Pega la lista exacta de 9 scopes |
Directory users.list HTTP 403 | admin_user= no es admin del Workspace | Usa un super-admin (o admin delegado con Usuarios→Lectura) |
Ráfagas de Gmail 403 rateLimitExceeded | >6.000 unidades de cuota/min/usuario | El plugin hace backoff automáticamente; para 1.500+ cuentas divide los jobs por rangos de usuarios |
history.list 404 en cada Incremental | historyId expirado (intervalo >1 semana) | Esperado — la ejecución recae en un recorrido completo y recrea el checkpoint |
Archivo de Drive omitido exceeds the 10 MB export cap | Archivo nativo de Google demasiado grande para files.export | Expórtalo manualmente o acepta la omisión (arreglo en el roadmap) |
Job falla backend completed without producing any virtual files | Credenciales malas / selección vacía | Ejecuta mode=verify; revisa los selectores del FileSet |
inline secret ... is forbidden (ADR-008) | sa_key=/password= en la línea Plugin= | Usa sa_key_file= (0600) |