Connecteur S3 / MinIO 🪣

Sauvegarde un bucket objet (MinIO ou tout stockage S3-compatible) en archivant tous les objets, et restaure en re-créant les objets via PutObject. SDK Go natif — pas de binaire externe.

  • Image : ilygo/bridge-minio:1 (distroless, ~15 MB)
  • Sous-commande : ilygo-bridge minio
  • Implémentation : github.com/minio/minio-go/v7 (compatible AWS S3, MinIO, Ceph RGW, Wasabi, etc.)

Variables d'environnement

En plus des variables communes :

Variable Obligatoire Description
MINIO_SOURCE_ENDPOINT oui Endpoint, ex : http://minio:9000 ou https://s3.example.com
MINIO_SOURCE_ACCESS oui Access key
MINIO_SOURCE_SECRET oui Secret key
MINIO_SOURCE_BUCKET oui Bucket source à sauvegarder
MINIO_SOURCE_TLS non 1 pour forcer TLS (sinon déduit du scheme de l'endpoint)

Prérequis côté stockage

L'access key doit pouvoir lister et lire le bucket source. Politique minimale (S3) :

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::mon-bucket" },
    { "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::mon-bucket/*" }
  ]
}

Pour la restauration, ajoutez s3:PutObject et s3:CreateBucket (côté MinIO : politique readwrite sur le bucket cible <bucket>-restored).

Déploiement (docker-compose)

services:
  app-minio:
    image: minio/minio:latest
    command: server /data
    networks: [app-net]

  ilygo-bridge:
    image: ilygo/bridge-minio:1
    restart: unless-stopped
    networks: [app-net, default]
    environment:
      ILYGO_ENDPOINT: https://backup.example/api/v1
      ILYGO_API_KEY: ik_xxx
      ILYGO_PASSPHRASE: ${ILYGO_PASSPHRASE}
      ILYGO_RESTORE_SECRET: 3f87d2022d95...
      ILYGO_LABEL: prod-assets-bucket
      MINIO_SOURCE_ENDPOINT: http://app-minio:9000
      MINIO_SOURCE_ACCESS: ${MINIO_ACCESS}
      MINIO_SOURCE_SECRET: ${MINIO_SECRET}
      MINIO_SOURCE_BUCKET: assets

networks:
  app-net:
    internal: true

Mécanisme de backup

  1. Liste récursivement tous les objets du bucket (ListObjects).
  2. Pour chaque objet : GetObject → ajoute une entrée dans une archive tar (clé = nom de l'objet).
  3. L'archive tar est compressée (zstd) puis chiffrée en chunks.

Les métadonnées d'objet (content-type, tags custom) ne sont pas préservées en v1 — seul le contenu + le chemin. Voir roadmap.

Mécanisme de restauration

Avec un RAT, le bridge déchiffre/décompresse l'archive tar, puis pour chaque objet PutObject dans le bucket cible :

side_by_side (recommandé) : bucket cible = <bucket>-restored (créé s'il n'existe pas). Ex : assetsassets-restored.

in_place (exige confirm_destructive) : ré-écrit les objets dans le bucket d'origine (écrase les objets de même clé ; ne supprime pas les objets ajoutés depuis le backup).

Réseau & sécurité

  • Aucun port exposé par le bridge ; stockage sur réseau internal: true.
  • Image distroless (pas de shell) — surface d'attaque minimale.
  • En prod : read_only: true, cap_drop: [ALL].

Dépannage

Symptôme Cause Solution
The specified bucket does not exist mauvais MINIO_SOURCE_BUCKET Vérifiez le nom exact
SignatureDoesNotMatch access/secret incorrects ou horloge décalée Vérifiez credentials + heure du conteneur
connection refused endpoint inaccessible / mauvais scheme http:// vs https://, alias réseau
restore : objets manquants gros buckets (tout en mémoire en v1) Voir limites ci-dessous

Limites & roadmap

  • v1 : archive tar en mémoire — adapté aux buckets jusqu'à quelques Go. Métadonnées non préservées.
  • Roadmap : streaming tar par objet (buckets To-scale), préservation des métadonnées + tags, restauration sélective par préfixe.