
MinIO est un serveur de stockage objet haute performance, compatible avec l'API Amazon S3. Beaucoup de déploiements s'arrêtent à « un bucket et deux clés d'accès » et passent à côté de l'essentiel : chiffrement au repos, versioning, verrouillage WORM, cycle de vie et surtout un contrôle d'accès fin avec fédération OIDC. Ce guide déploie MinIO puis active ces fonctions une par une, chaque commande étant vérifiée sur une instance réelle (release RELEASE.2025-09-07). Public visé : administrateurs et DevOps à l'aise avec la ligne de commande et l'API S3.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Déployer MinIO avec le chiffrement au repos activé dès le départ (KMS)
- Activer versioning, Object Lock WORM et cycle de vie des objets
- Restreindre un utilisateur à un préfixe précis d'un bucket
- Fédérer les identités via OIDC et délivrer des accès temporaires STS
- Ajouter tagging, URL présignées, notifications et réplication
Prérequis
Section intitulée « Prérequis »- Un hôte Linux avec Docker (ou le binaire MinIO et un service systemd).
- Le client
mc(MinIO Client) etaws-clipour tester l'API S3. - Pour la partie OIDC : un fournisseur d'identité (Keycloak, Authentik, Dex...).
Installer MinIO avec le chiffrement activé
Section intitulée « Installer MinIO avec le chiffrement activé »Le piège classique est de démarrer MinIO sans KMS : le chiffrement côté serveur (SSE-S3) est alors refusé. On active donc le KMS dès l'installation, avec une clé maître passée en variable d'environnement. C'est la configuration qui débloque le chiffrement au repos.
# Générer une clé maître de 32 octets encodée en base64KMS_KEY=$(head -c 32 /dev/urandom | base64)
docker run -d --name minio \ -p 9000:9000 -p 9001:9001 \ -e MINIO_ROOT_USER=labadmin \ -e MINIO_ROOT_PASSWORD=labsecret123 \ -e "MINIO_KMS_SECRET_KEY=cle-maitre:${KMS_KEY}" \ -v /data/minio:/data \ quay.io/minio/minio:latest server /data --console-address ":9001"La variable MINIO_KMS_SECRET_KEY au format nom:clé-base64 active un KMS interne à une clé, suffisant pour du chiffrement au repos. Vérifiez que le serveur répond :
curl -s http://127.0.0.1:9000/minio/health/live # réponse vide = OKLe client mc et le premier bucket
Section intitulée « Le client mc et le premier bucket »mc pilote MinIO en ligne de commande. On enregistre d'abord un alias vers le serveur, puis on crée un bucket.
mc alias set local http://127.0.0.1:9000 labadmin labsecret123mc mb local/datamc admin info local # état du serveur, version, disquesLa sortie de mc admin info confirme la version et l'état des disques. À partir de là, aws-cli fonctionne aussi contre le même endpoint (--endpoint-url http://127.0.0.1:9000), utile pour tester la compatibilité S3 de vos applications.
Chiffrement au repos (SSE-S3)
Section intitulée « Chiffrement au repos (SSE-S3) »Le KMS étant actif, on peut chiffrer les objets côté serveur. On force le chiffrement par défaut sur le bucket, pour que tout objet déposé soit chiffré sans que le client ait à le demander.
# Chiffrement automatique de tout objet écrit dans le bucketaws --endpoint-url http://127.0.0.1:9000 s3api put-bucket-encryption \ --bucket data \ --server-side-encryption-configuration \ '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
# Un objet déposé est alors chiffré (SSE-S3 / AES256)echo secret > f.txtaws --endpoint-url http://127.0.0.1:9000 s3 cp f.txt s3://data/f.txtaws --endpoint-url http://127.0.0.1:9000 s3api head-object --bucket data --key f.txt \ --query ServerSideEncryption --output text# -> AES256Le champ ServerSideEncryption: AES256 dans la réponse head-object prouve que l'objet est chiffré au repos. Sans le KMS configuré à l'étape précédente, put-object --server-side-encryption AES256 renverrait une erreur.
Versioning et récupération
Section intitulée « Versioning et récupération »Le versioning conserve chaque version d'un objet et transforme une suppression en delete marker réversible. C'est le filet de sécurité contre l'écrasement et la suppression accidentelle.
mc version enable local/data
# Deux écritures successives = deux versionsecho v1 > o.txt; mc cp o.txt local/data/o.txtecho v2 > o.txt; mc cp o.txt local/data/o.txtmc ls --versions local/data/o.txtUne suppression crée un delete marker sans effacer les versions ; on peut donc restaurer l'état précédent en ciblant un VersionId :
aws --endpoint-url http://127.0.0.1:9000 s3api delete-object --bucket data --key o.txt# l'objet "disparait" (delete marker) mais les versions restentaws --endpoint-url http://127.0.0.1:9000 s3api list-object-versions --bucket data --prefix o.txt \ --query 'Versions[].VersionId'# récupération d'une version préciseaws --endpoint-url http://127.0.0.1:9000 s3api get-object --bucket data --key o.txt \ --version-id <VersionId> restaure.txtObject Lock : verrouillage WORM
Section intitulée « Object Lock : verrouillage WORM »Pour la conformité (sauvegardes inaltérables, journaux légaux), MinIO propose Object Lock en mode WORM (write once, read many) : un objet verrouillé ne peut pas être supprimé avant la fin de sa rétention. Object Lock exige un bucket créé avec le verrouillage activé (le versioning est alors automatique).
aws --endpoint-url http://127.0.0.1:9000 s3api create-bucket \ --bucket coffre --object-lock-enabled-for-bucket
# Déposer un objet avec une rétention de 30 jours en mode GOVERNANCEaws --endpoint-url http://127.0.0.1:9000 s3api put-object \ --bucket coffre --key rapport.pdf --body rapport.pdf \ --object-lock-mode GOVERNANCE \ --object-lock-retain-until-date 2026-08-16T00:00:00ZToute tentative de suppression de la version verrouillée est refusée tant que la rétention court. Le mode COMPLIANCE est encore plus strict : même le compte root ne peut pas lever la rétention avant son terme, là où GOVERNANCE autorise un contournement par un utilisateur habilité (s3:BypassGovernanceRetention).
Cycle de vie des objets
Section intitulée « Cycle de vie des objets »Le cycle de vie (lifecycle) automatise l'expiration des objets et le nettoyage des versions anciennes ou des uploads multipart incomplets. Indispensable pour maîtriser le coût de stockage d'un bucket versionné.
aws --endpoint-url http://127.0.0.1:9000 s3api put-bucket-lifecycle-configuration \ --bucket data --lifecycle-configuration '{ "Rules": [ { "ID": "expire-30j", "Status": "Enabled", "Filter": {"Prefix": "logs/"}, "Expiration": {"Days": 30} }, { "ID": "purge-multipart", "Status": "Enabled", "Filter": {}, "AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 7} } ] }'La première règle expire les objets sous logs/ après 30 jours ; la seconde purge les uploads multipart abandonnés après 7 jours. Le contrôleur de cycle de vie de MinIO applique ces règles en arrière-plan.
Contrôle d'accès : utilisateurs et politiques
Section intitulée « Contrôle d'accès : utilisateurs et politiques »MinIO embarque un moteur de politiques au format IAM. On crée un utilisateur (ou un compte de service) et on lui attache une politique. Les politiques prédéfinies readonly, readwrite, writeonly couvrent les cas simples ; les vraies restrictions passent par une politique sur mesure.
mc admin user add local alice AliceSecret123mc admin policy attach local readonly --user alice # exemple simpleRestreindre un utilisateur à un préfixe
Section intitulée « Restreindre un utilisateur à un préfixe »C'est le besoin fréquent en multi-équipes : chaque équipe ne voit que son préfixe dans un bucket partagé. La politique combine une autorisation ciblée sur data/team-a/* pour les objets et une condition s3:prefix pour le listage.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": ["arn:aws:s3:::data"], "Condition": { "StringLike": { "s3:prefix": ["team-a/*"] } } }, { "Effect": "Allow", "Action": ["s3:GetObject","s3:PutObject","s3:DeleteObject"], "Resource": ["arn:aws:s3:::data/team-a/*"] } ]}mc admin policy create local team-a-only team-a-policy.jsonmc admin policy attach local team-a-only --user aliceRésultat vérifié : avec ces droits, alice lit et écrit sous team-a/ mais reçoit un AccessDenied (403) sur team-b/, y compris pour lister le préfixe voisin. C'est le cloisonnement par préfixe dans un bucket unique.
Fédération OIDC et accès temporaires (STS)
Section intitulée « Fédération OIDC et accès temporaires (STS) »Plutôt que de distribuer des clés statiques, on fédère l'authentification à un fournisseur d'identité (Keycloak, Authentik, Dex...). L'utilisateur se connecte à l'IdP, obtient un jeton OIDC, puis l'échange contre des identifiants temporaires via STS AssumeRoleWithWebIdentity. Ces identifiants portent la politique par préfixe vue plus haut : l'accès est scopé et expire tout seul.
-
Déclarer le fournisseur OIDC dans MinIO, en pointant sur une politique existante via
role_policy:Fenêtre de terminal mc admin config set local identity_openid \config_url="https://idp.example.com/.well-known/openid-configuration" \client_id="minio" client_secret="<secret>" \scopes="openid" role_policy="team-a-only"mc admin service restart localAu redémarrage, MinIO génère un ARN de rôle (
arn:minio:iam:::role/<hash>) visible dans les logs : c'est lui que l'échange STS ciblera. -
Obtenir un jeton OIDC auprès de l'IdP (ici via le flux d'authentification de votre application ou, pour tester, le grant approprié de l'IdP), puis l'échanger contre des identifiants temporaires. L'appel STS se fait en POST :
Fenêtre de terminal curl -s -X POST http://127.0.0.1:9000/ \--data-urlencode "Action=AssumeRoleWithWebIdentity" \--data-urlencode "Version=2011-06-15" \--data-urlencode "DurationSeconds=3600" \--data-urlencode "RoleArn=arn:minio:iam:::role/<hash>" \--data-urlencode "WebIdentityToken=<jeton-oidc>"La réponse XML contient un
AccessKeyId, unSecretAccessKeyet unSessionTokentemporaires. -
Utiliser les identifiants temporaires (avec le
SessionToken) : l'accès est limité au préfixe de la politique et expire au bout de la durée demandée.Fenêtre de terminal export AWS_ACCESS_KEY_ID=<temp> AWS_SECRET_ACCESS_KEY=<temp> AWS_SESSION_TOKEN=<temp>aws --endpoint-url http://127.0.0.1:9000 s3 cp s3://data/team-a/f.txt . # OKaws --endpoint-url http://127.0.0.1:9000 s3 cp s3://data/team-b/f.txt . # AccessDenied
Autres fonctions utiles
Section intitulée « Autres fonctions utiles »Une fois le socle en place, quelques activations complètent le déploiement.
-
Tagging d'objets : classez et pilotez le cycle de vie par tag.
Fenêtre de terminal aws --endpoint-url http://127.0.0.1:9000 s3api put-object-tagging --bucket data --key f.txt \--tagging 'TagSet=[{Key=classe,Value=confidentiel}]' -
URL présignée : partager un objet en lecture pour une durée limitée, sans exposer de clé.
Fenêtre de terminal mc share download --expire 1h local/data/f.txt -
Notifications d'événements : déclencher un traitement à chaque dépôt d'objet (webhook, file d'attente). On enregistre une cible (par exemple un webhook) dans la configuration, puis on l'associe au bucket.
-
Réplication : MinIO propose la site replication (
mc admin replicate add) pour synchroniser plusieurs sites MinIO, et la réplication de bucket vers une cible S3. Elle s'appuie sur le versioning activé plus haut.
Sécurité et points de vigilance
Section intitulée « Sécurité et points de vigilance »- Activez TLS : placez
private.keyetpublic.crtdans~/.minio/certs/(ou/root/.minio/certs/en conteneur) ; MinIO les détecte au démarrage. Le SSE-C (clés fournies par le client) exige d'ailleurs TLS. - Changez la clé root après le bootstrap et créez des comptes de service dédiés par application, jamais la clé root dans un pipeline.
- Moindre privilège : préférez les politiques par préfixe et les identifiants temporaires STS aux clés statiques à large portée.
- Sauvegardez la configuration (
mc admin cluster bucket export, export des politiques et des identités) avant toute montée de version.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
put-object --server-side-encryption refusé | KMS non configuré | Démarrer avec MINIO_KMS_SECRET_KEY (ou KES) |
| STS renvoie des identifiants vides | Appel AssumeRoleWithWebIdentity en GET | Envoyer la requête en POST |
OIDC ignoré après config set | Serveur non redémarré | mc admin service restart puis vérifier mc admin config get identity_openid |
| Suppression d'un objet verrouillé impossible | Object Lock actif (attendu) | Attendre la fin de rétention ou lever en GOVERNANCE avec le droit de bypass |
Access Denied sur un préfixe | Politique scopée trop stricte ou s3:prefix manquant | Vérifier la condition s3:prefix et le Resource de la politique |
À retenir
Section intitulée « À retenir »- Sans KMS (
MINIO_KMS_SECRET_KEYou KES), pas de chiffrement SSE-S3 : activez-le dès l'installation. - Le versioning transforme les suppressions en delete markers réversibles ; l'Object Lock WORM rend les objets inaltérables pour la conformité.
- Le cycle de vie maîtrise le coût d'un bucket versionné (expiration, purge multipart).
- Une politique par préfixe (
Resourceciblé + conditions3:prefix) cloisonne les équipes dans un bucket unique. - La fédération OIDC + STS
AssumeRoleWithWebIdentitydélivre des accès temporaires et scopés ; l'appel STS se fait en POST. - L'édition communautaire reste AGPLv3 et fonctionnelle ; l'administration se pilote en CLI/IaC depuis le retrait de la console.