Copiar objetos de un bucket a otro es trivial. Lo que no es trivial es hacerlo entre proveedores distintos, de forma repetible, sin dejar claves estáticas en disco, sin otorgar permisos sobre la tenancy entera a una tarea que solo necesita un bucket, y sabiendo de antemano cuánto va a crecer la factura.
Este texto describe el camino de OCI Object Storage hacia Amazon S3. La dirección inversa cambia los nombres de las primitivas, no el razonamiento.
Por qué cruzar de nube
La durabilidad de medios que anuncian los proveedores no es el riesgo que cubre la copia entre nubes. Esta existe para cubrir lo que la durabilidad no cubre: credencial administrativa comprometida, borrado masivo ejecutado por tu propia automatización, cuenta suspendida, error de política que eliminó lo que el ciclo de vida debía haber conservado. Todo eso ocurre dentro de la frontera de la cuenta, y la replicación dentro de la misma cuenta hereda esa frontera.
La regla es la misma que separa copia de espejo: el destino no puede obedecer a quien controla el origen. Ya tratamos esa distinción en backup no es sincronización.
El diseño mínimo
Tres piezas: una identidad de lectura en el origen, una identidad de escritura en el destino y un proceso que se ejecuta en algún lugar. La decisión más importante es dónde corre ese proceso, porque define cuál de las dos credenciales puede ser una identidad de máquina y cuál será, inevitablemente, una clave estática.
- Worker en el origen (OCI). Lectura mediante instance principal — sin secretos en archivo. La clave estática pasa a ser la de AWS, con permiso de escritura en el destino.
- Worker en el destino (AWS). Escritura mediante IAM role de la instancia. La clave estática pasa a ser la de OCI, con permiso de lectura en el origen.
No existe una opción sin ninguna clave estática, salvo que uses federación entre ambos proveedores. Lo que existe es la elección sobre qué filtración prefieres. Una clave de lectura filtrada expone el contenido del bucket de origen. Una clave de escritura filtrada alcanza el destino — y por eso el destino necesita Object Lock y una identidad que no pueda borrar, tema de backup inmutable con Object Lock.
Paso a paso
1. Inventariar el origen. Namespace del Object Storage, compartimento, región, nombre exacto del bucket. Cantidad aproximada de objetos y distribución de tamaños. Si el bucket tiene versionado, decidir si copias solo la versión actual o el histórico — son proyectos distintos en esfuerzo y en costo.
2. Crear la identidad de lectura, con alcance de bucket. En OCI la política se escribe
por compartimento, pero admite condición de recurso. El formato es
allow group BackupLectura to read objects in compartment <nombre> where target.bucket.name='<bucket>'.
Sin la condición where, acabas de dar lectura de todos los buckets del compartimento a una
tarea que necesita uno. En un entorno de MSP eso basta para que un cliente alcance los datos
de otro — tema de
cómo impedir que el backup de un cliente toque el de otro.
3. Decidir entre API nativa y compatibilidad S3. OCI expone una API compatible con S3, lo que te permite usar herramientas que ya hablan S3 en ambos extremos. El precio es que esa vía depende de una customer secret key — par de claves estático ligado a un usuario — y tiene diferencias de implementación respecto de la API nativa. El SDK nativo acepta instance principal y prescinde de secretos, al costo de escribir código propio para listar y leer. Consulta la documentación de Object Storage de OCI antes de elegir.
4. Preparar el destino. Bucket dedicado, uno por cliente. Versionado activado. Object
Lock habilitado — decidirlo en la creación es el camino más simple; habilitarlo después es
posible en un bucket versionado, y el procedimiento actual está en la
documentación de Object Lock en S3.
Política de bucket que ate el Principal al ARN exacto del role o del usuario que escribe, y
que deniegue s3:DeleteObject, s3:DeleteObjectVersion y, si hay retención configurada,
s3:PutObjectRetention y s3:PutObjectLegalHold para ese principal. En un bucket versionado,
denegar solo s3:DeleteObject no impide la eliminación de versiones. Quien escribe no borra.
Los roles de IAM resuelven
la parte de identidad de máquina; la política de bucket resuelve la parte de alcance.
5. Transferir. En un bucket con millones de objetos pequeños, el cuello de botella casi nunca es el ancho de banda: es el listado y la cantidad de solicitudes. Paraleliza por prefijo, usa multipart solo por encima de un umbral que tenga sentido y mantén un índice propio de lo ya copiado — releer el origen entero en cada ciclo es lo que convierte un backup barato en caro. El efecto del volumen de archivos pequeños sobre la factura está en costo de backup de millones de archivos pequeños.
6. Verificar. Comparar tamaños es necesario e insuficiente. El ETag de un objeto enviado por multipart no es el MD5 del contenido, así que comparar ETags entre proveedores produce falsos negativos. Calcula y guarda un checksum propio por objeto en tu índice, o usa los campos de checksum adicionales que ofrece S3. La documentación de integridad de objetos de Amazon S3 describe qué algoritmos pueden enviarse junto con el objeto.
7. Programar y observar. Ciclo con reporte de objetos nuevos, objetos modificados y fallos. Un backup que no reporta fallos es un backup que crees tener.
Las trampas
El egreso se cobra en el origen. La estructura típica incluye cobro por solicitud (LIST, GET y PUT cuentan por separado), cobro por volumen de salida de datos y cobro por almacenamiento en la clase elegida. Las clases frías suman dos cláusulas que pillan desprevenida a la gente: mínimo de días de retención facturados y multa por eliminación anticipada. No repito precios aquí porque las tablas cambian; abre la página de precios de la región exacta de tu bucket y suma los tres componentes antes de lanzar el primer ciclo. Lo que suele desaparecer de la cuenta está en lo que desaparece de la factura de un almacenamiento barato.
La credencial de origen necesita escritura si hay restauración de vuelta. Esta trampa
aparece el día del incidente, no en la configuración. Configuraste lectura en el origen,
escritura en el destino, todo con privilegio mínimo — y el día del incidente descubres que
nadie puede escribir de vuelta en el bucket de origen. La salida no es dar escritura a la
identidad de backup. Es crear una segunda identidad, de restauración, con manage objects
en el bucket de origen y ningún permiso en el destino más allá de lectura, mantenida
desactivada en operación normal y habilitada mediante un procedimiento explícito. Quien
aprueba la reactivación no debería ser quien opera el backup. Y el procedimiento tiene que
haberse ejecutado en un simulacro, si no es un documento, no una capacidad.
Los metadatos no cruzan solos. Clase de almacenamiento, etiquetas, ACLs, pre-authenticated requests, reglas de ciclo de vida y configuración del bucket no son objetos. Copiar objetos no es respaldar la configuración — esa parte vive en infraestructura como código, versionada en un repositorio.
Claves raras. Objetos de cero bytes terminados en barra, claves con #, ?, acentos o
espacios, y profundidad de prefijo mayor que la que acepta el sistema de archivos de destino,
en caso de que pases por disco. Trata la clave como una secuencia de bytes opaca, nunca como
una ruta.
La restauración fría lleva tiempo. Escribir en una clase de archivado en el destino es lo que hace que las cuentas cierren, y el costo de eso es el tiempo de rescate. Vale la pena leer restauración en Deep Archive en la práctica y por qué el restore es la parte que nadie antes de prometerle un RTO al cliente.
Lo que este artículo no prueba
Aquí no hay ninguna medición de rendimiento. Ningún número de throughput, de tiempo de listado ni de costo mensual — porque las tablas de precios y los límites de API cambian por región y por cuenta, y un número equivocado en un texto técnico es peor que ningún número.
Y el consejo no sirve para todo el mundo:
- Bucket pequeño y único. Si son unos pocos gigabytes en un solo bucket,
rcloneen un cron con la clave bien guardada suele bastar. La arquitectura descrita arriba solo se paga cuando hay muchos clientes, muchos buckets y necesidad de demostrar alcance. - La amenaza es falla de infraestructura, no acción humana. En ese caso, la replicación dentro de la misma nube es más simple, más barata y más rápida de restaurar. Cruzar de proveedor es cobertura contra la pérdida de control de la cuenta — si ese riesgo no está en tu modelo de amenazas, estás pagando egreso en vano.
- RTO corto. La copia entre nubes, en especial en clase fría, es peor en tiempo de recuperación que la replicación regional. Quien necesita minutos necesita ambas cosas, no una.
- Equipo pequeño. Dos identidades por cliente, rotación de claves estáticas y procedimiento de break-glass son costo operativo continuo. Una automatización mal mantenida aquí genera más incidentes de los que previene.
Checklist
- Permiso de lectura con condición por nombre de bucket, nunca por compartimento entero.
- Identidad de máquina en el extremo donde corre el worker; clave estática solo en el otro, con rotación programada y custodia en una bóveda.
- Bucket de destino dedicado, versionado, con Object Lock habilitado — en la creación es el camino más simple; en un bucket versionado se puede habilitar después, verificando el procedimiento actual en la documentación de S3.
- Identidad de escritura sin permiso de eliminación de objetos ni de versiones, atada por política de bucket.
- Índice propio con checksum, sin depender del ETag entre proveedores.
- Identidad de restauración separada, con escritura en el origen, desactivada por defecto.
- Configuración del bucket versionada en IaC, aparte de los objetos.
- Restauración cronometrada al menos una vez, con las identidades reales.
NubliVault es el producto de backup de Nublify: empaqueta millones de archivos pequeños y los guarda en una nube distinta a la de origen. Cómo funciona · Seguridad