xpeditis2.0/docs/mise-en-prod/07-stockage-objet-s3.md
David b22f4e0b74 docs: procedure de mise en production pas a pas
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
2026-09-07 21:40:50 +02:00

6.0 KiB

07 — Stockage objet (Hetzner Object Storage)

Durée : environ 45 min.

Hetzner Object Storage remplace MinIO en production. C'est un service compatible S3 : aucune ligne de code applicatif ne change, seules les variables AWS_S3_ENDPOINT, AWS_REGION et les clés diffèrent.

MinIO auto-hébergé Hetzner Object Storage
Coût « gratuit » + le disque + votre temps ~6 €/To/mois
À sauvegarder oui, un volume de plus non, réplication incluse
CVE à suivre oui non
Console à protéger oui non
Perte si app-01 brûle totale aucune

Le dernier point suffit à trancher : les connaissements et confirmations de réservation sont des documents contractuels.


1. Créer les buckets

Console Hetzner → projet xpeditis-prod → Object Storage → région fsn1.

Créez deux buckets :

Bucket Contenu Visibilité
xpeditis-prod-documents PDF, connaissements, imports CSV Privé
xpeditis-prod-pgbackup Sauvegardes WAL-G Privé

Deux buckets, deux jeux de clés. Si les clés applicatives fuitent (fuite de secret, faille d'injection), l'attaquant atteint les documents mais pas les sauvegardes. C'est précisément ce qui permet de se relever d'un rançongiciel. Ne mutualisez pas.

Vérifiez que les deux sont bien en Private. Un bucket public exposerait des documents commerciaux nominatifs à toute personne devinant une URL.


2. Créer les clés d'accès

Object Storage → Credentials → Generate credentials, deux fois :

Nom Bucket Destination
xpeditis-app xpeditis-prod-documents Secret Kubernetes AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
xpeditis-walg xpeditis-prod-pgbackup .env.data de db-01, WALG_ACCESS_KEY_ID / WALG_SECRET_ACCESS_KEY

Le secret n'est affiché qu'une fois. Copiez-le immédiatement.

Hetzner Object Storage ne propose pas encore de politique par bucket aussi fine qu'AWS IAM. La séparation repose donc sur l'usage de deux jeux de clés distincts, chacun n'étant présent qu'à un seul endroit. Ne copiez jamais les clés WAL-G dans un Secret Kubernetes.


3. Configuration applicative

Déjà en place dans infra/prod/k8s/base/02-configmap-backend.yaml :

AWS_REGION: "fsn1"
AWS_S3_ENDPOINT: "https://fsn1.your-objectstorage.com"
AWS_S3_BUCKET: "xpeditis-prod-documents"

Les clés vont dans le Secret (06) :

AWS_ACCESS_KEY_ID: "<clé xpeditis-app>"
AWS_SECRET_ACCESS_KEY: "<secret xpeditis-app>"

Et WAL-G dans .env.data sur db-01 (04) :

WALG_S3_PREFIX=s3://xpeditis-prod-pgbackup
WALG_S3_ENDPOINT=https://fsn1.your-objectstorage.com
WALG_S3_REGION=fsn1
WALG_ACCESS_KEY_ID=<clé xpeditis-walg>
WALG_SECRET_ACCESS_KEY=<secret xpeditis-walg>

4. Vérifier

Avec le client AWS ou s3cmd :

export AWS_ACCESS_KEY_ID='<clé xpeditis-app>'
export AWS_SECRET_ACCESS_KEY='<secret xpeditis-app>'

# Lister
aws --endpoint-url https://fsn1.your-objectstorage.com s3 ls s3://xpeditis-prod-documents/

# Écrire puis relire
echo "test $(date -Is)" > /tmp/test.txt
aws --endpoint-url https://fsn1.your-objectstorage.com s3 cp /tmp/test.txt s3://xpeditis-prod-documents/
aws --endpoint-url https://fsn1.your-objectstorage.com s3 cp s3://xpeditis-prod-documents/test.txt -
aws --endpoint-url https://fsn1.your-objectstorage.com s3 rm s3://xpeditis-prod-documents/test.txt

Le bucket est-il vraiment privé ?

curl -sI https://fsn1.your-objectstorage.com/xpeditis-prod-documents/test.txt | head -1

Attendu : HTTP/1.1 403 Forbidden. Si vous obtenez 200, le bucket est public : corrigez immédiatement.

Les clés sont-elles bien cloisonnées ?

# Les clés applicatives ne doivent PAS voir le bucket de sauvegarde
aws --endpoint-url https://fsn1.your-objectstorage.com s3 ls s3://xpeditis-prod-pgbackup/

Un refus est le résultat attendu. S'il réussit, vous avez utilisé les mêmes clés pour les deux : régénérez-en un jeu séparé.


5. Durée de conservation

Une règle de cycle de vie évite que les documents s'accumulent indéfiniment — utile pour la facture comme pour le RGPD (16).

Attention : les documents contractuels maritimes ont des obligations de conservation longues (généralement 10 ans en France pour les pièces comptables). Ne posez pas de règle de suppression automatique sur xpeditis-prod-documents sans validation juridique.

Sur xpeditis-prod-pgbackup, en revanche, la purge est gérée par WAL-G (wal-g delete retain FULL 7, dans pg-backup.sh). N'ajoutez pas de règle de cycle de vie côté bucket : les deux mécanismes se contrediraient et vous risqueriez de supprimer des WAL encore nécessaires à une restauration.


6. Et le CDN ?

Le fichier de prévisions retient Bunny.net (0,005 €/Go, ~1 €/mois en phase 1) comme CDN si Hetzner est choisi.

Ce n'est pas nécessaire au lancement. Cloudflare met déjà en cache les ressources statiques de Next.js (/_next/static/*) gratuitement, et le trafic de la phase 1 (10 Go/mois selon les hypothèses) ne justifie pas un service supplémentaire.

Reconsidérez la question quand :

  • le trafic sortant dépasse 500 Go/mois ; ou
  • des utilisateurs hors d'Europe se plaignent de la latence ; ou
  • vous servez des documents volumineux directement depuis Object Storage.

7. Contrôle

[ ] Bucket xpeditis-prod-documents créé, PRIVÉ
[ ] Bucket xpeditis-prod-pgbackup créé, PRIVÉ
[ ] Deux jeux de clés DISTINCTS générés
[ ] Écriture / lecture / suppression testées sur le bucket documents
[ ] Accès HTTP anonyme : 403
[ ] Les clés applicatives ne peuvent PAS lire le bucket de sauvegarde
[ ] Clés applicatives dans le Secret Kubernetes
[ ] Clés WAL-G uniquement dans .env.data de db-01
[ ] Aucune règle de cycle de vie sur le bucket de sauvegarde

→ Suite : 08 — DNS, TLS, Cloudflare