Mesuré le 2026-09-07, avec les identifiants du compte de service kadans-app
Le même objet, les mêmes identifiants, deux chemins :
requête
par s3.arcodange.fr
en direct sur MinIO (port-forward)
PUT (déposer)
✅ OK
✅ OK
GET (relire les octets)
✅ OK
✅ OK
HEAD (relire l'en-tête)
❌403 Forbidden
✅OK
HEAD d'un objet ABSENT
❌ 403 Forbidden
✅ 404 Not Found
DELETE
✅ OK
✅ OK
Pourquoi ce n'est ni MinIO ni la politique
Trois raisons, chacune suffisante :
En direct, HEAD passe — même clé, même signature SigV4, même compte.
L'erreur n'a pas la forme d'une erreur S3. MinIO répond AccessDenied dans un corps XML ; ici c'est un « Forbidden » nu, sans code S3.
Un objet absent devrait rendre 404, et c'est bien ce que MinIO fait en direct. Par le bord, il rend 403 lui aussi — donc la requête est rejetée avant d'atteindre le magasin.
Le suspect est donc au bord : Traefik, une middleware, CrowdSec, ou ce qui se trouve devant. Ce n'est pas un défaut de la politique IAM, qui vient d'être vérifiée des deux côtés dans arcodange/kadans#1033.
Ce que ça coûte aujourd'hui, et ce que ça coûtera
Aujourd'hui : rien. Le dépôt de vidéos de Kadans n'utilise que PUT et GET, et la relecture des octets fonctionne. Ce n'est pas un incident en cours.
Demain, oui : HEAD est la façon normale et bon marché de demander « cet objet existe-t-il, et combien pèse-t-il ? » sans rapatrier les octets. Tout code qui sonderait l'existence d'une vidéo depuis le navigateur — une reprise de téléversement, une vérification avant affichage, un contrôle d'intégrité — tomberait sur un 403 qui accuserait la politique IAM, c'est-à-dire le mauvais coupable. C'est précisément le genre de faux coupable qui coûte une session entière.
Ce que je n'ai pas vérifié
Quelle brique refuse, exactement. Je n'ai pas lu la configuration du bord ni ses journaux.
Si d'autres méthodes sont filtrées pareil (OPTIONS, POST sur d'autres routes). ⚠ Le préflight CORS du magasin a son propre gate côté front (bun run check:cors) — à relire si OPTIONS était concerné.
Si c'est voulu (un durcissement délibéré) ou subi. Si c'est voulu, la raison mérite d'être écrite là où quelqu'un la lira avant d'accuser la politique.
## Mesuré le 2026-09-07, avec les identifiants du compte de service `kadans-app`
Le même objet, les mêmes identifiants, deux chemins :
| requête | par `s3.arcodange.fr` | en direct sur MinIO (port-forward) |
|---|---|---|
| `PUT` (déposer) | ✅ OK | ✅ OK |
| `GET` (relire les octets) | ✅ OK | ✅ OK |
| **`HEAD`** (relire l'en-tête) | ❌ **403 Forbidden** | ✅ **OK** |
| `HEAD` d'un objet **ABSENT** | ❌ 403 Forbidden | ✅ 404 Not Found |
| `DELETE` | ✅ OK | ✅ OK |
## Pourquoi ce n'est ni MinIO ni la politique
Trois raisons, chacune suffisante :
1. **En direct, HEAD passe** — même clé, même signature SigV4, même compte.
2. **L'erreur n'a pas la forme d'une erreur S3.** MinIO répond `AccessDenied` dans un corps XML ; ici c'est un « Forbidden » nu, sans code S3.
3. **Un objet absent devrait rendre 404**, et c'est bien ce que MinIO fait en direct. Par le bord, il rend 403 lui aussi — donc la requête est rejetée **avant** d'atteindre le magasin.
Le suspect est donc au bord : Traefik, une middleware, CrowdSec, ou ce qui se trouve devant. Ce n'est **pas** un défaut de la politique IAM, qui vient d'être vérifiée des deux côtés dans [arcodange/kadans#1033](https://gitea.arcodange.lab/arcodange/kadans/issues/1033).
## Ce que ça coûte aujourd'hui, et ce que ça coûtera
**Aujourd'hui : rien.** Le dépôt de vidéos de Kadans n'utilise que `PUT` et `GET`, et la relecture des octets fonctionne. Ce n'est pas un incident en cours.
**Demain, oui** : `HEAD` est la façon normale et bon marché de demander « cet objet existe-t-il, et combien pèse-t-il ? » sans rapatrier les octets. Tout code qui sonderait l'existence d'une vidéo depuis le navigateur — une reprise de téléversement, une vérification avant affichage, un contrôle d'intégrité — tomberait sur un 403 **qui accuserait la politique IAM**, c'est-à-dire le mauvais coupable. C'est précisément le genre de faux coupable qui coûte une session entière.
## Ce que je n'ai pas vérifié
- **Quelle brique refuse**, exactement. Je n'ai pas lu la configuration du bord ni ses journaux.
- Si d'autres méthodes sont filtrées pareil (`OPTIONS`, `POST` sur d'autres routes). ⚠ Le préflight CORS du magasin a son propre gate côté front (`bun run check:cors`) — à relire si `OPTIONS` était concerné.
- Si c'est **voulu** (un durcissement délibéré) ou **subi**. Si c'est voulu, la raison mérite d'être écrite là où quelqu'un la lira avant d'accuser la politique.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
⚠⚠ CORRECTION — cette issue était fausse sur deux points
Remesuré le 2026-09-08, avec les mêmes identifiants, en lisant cette fois les en-têtes de la réponse. Ce que j'avais écrit ne tient pas.
Ce que j'avais dit, et ce qui est vrai
affirmation de l'issue
mesure réelle
« le bord refuse les requêtes HEAD »
faux — HEAD passe : cinq d'affilée, tous 200
« un objet absent rend 403 par le bord »
faux — il rend 404 avec x-minio-error-code: NoSuchKey
« l'erreur n'a pas la forme d'une erreur S3, donc ce n'est pas MinIO »
faux — la réponse porte bien x-minio-error-code et x-amz-request-id : c'est MinIO qui répond
Mon erreur de méthode est nette : une réponse à un HEAD n'a pas de corps, donc le XML d'erreur de S3 est absent et boto3 rapporte un « 403 Forbidden » nu. J'en ai conclu que l'erreur ne venait pas de S3. Le code d'erreur était dans un en-tête que je n'avais pas regardé. J'ai lu une absence produite par le protocole et j'y ai vu une signature.
Le phénomène réel, beaucoup plus étroit
HEAD objet PRÉSENT (juste après le PUT) → REFUSÉ HTTP 403 (aucun code MinIO)
HEAD objet ABSENT → 404 NoSuchKey ← correct
GET objet présent → 200 ← correct
--- un instant plus tard ---
HEAD #1..#5 → 200, 200, 200, 200, 200
Un HEAD émis immédiatement après le PUT de la même clé peut rendre 403 une fois, puis réussir. C'est une affaire de temps, pas de droit : la politique est la même dans les deux cas, et l'objet absent est correctement rapporté.
⚠ Je n'ai pas la cause.server: cloudflare est dans la chaîne, et une lecture juste après écriture à travers un CDN est un suspect naturel — mais c'est une hypothèse, pas un diagnostic. Le middleware CrowdSec (kube-system-crowdsec@kubernetescrd) est aussi sur cet ingress, et une rafale de 403 depuis mon poste pendant les essais du matin a pu déclencher une limitation ; ça expliquerait pourquoi le même geste échouait en série puis passe aujourd'hui.
Ce que ça change pour la suite
L'issue reste ouverte mais change de nature : ce n'est plus « HEAD est bloqué », c'est « une lecture juste après écriture peut rendre un 403 isolé ». Le risque pour Kadans est faible — le dépôt n'enchaîne pas PUT puis HEAD — mais il est réel pour tout code qui voudrait vérifier son écriture dans la foulée : il verrait un refus de droit là où il n'y en a pas.
⚠ Et la leçon vaut plus que le défaut : j'ai publié un diagnostic sur une absence qui appartenait à mon instrument, exactement le piège que ce dépôt documente. La correction a coûté une commande.
## ⚠⚠ CORRECTION — cette issue était fausse sur deux points
Remesuré le 2026-09-08, avec les mêmes identifiants, en lisant cette fois les **en-têtes** de la réponse. Ce que j'avais écrit ne tient pas.
### Ce que j'avais dit, et ce qui est vrai
| affirmation de l'issue | mesure réelle |
|---|---|
| « **le bord refuse les requêtes HEAD** » | **faux** — HEAD passe : cinq d'affilée, tous `200` |
| « un objet **absent** rend 403 par le bord » | **faux** — il rend `404` avec `x-minio-error-code: NoSuchKey` |
| « l'erreur n'a pas la forme d'une erreur S3, donc ce n'est pas MinIO » | **faux** — la réponse porte bien `x-minio-error-code` et `x-amz-request-id` : **c'est MinIO qui répond** |
**Mon erreur de méthode est nette** : une réponse à un `HEAD` n'a **pas de corps**, donc le XML d'erreur de S3 est absent et boto3 rapporte un « 403 Forbidden » nu. J'en ai conclu que l'erreur ne venait pas de S3. Le code d'erreur était dans un **en-tête** que je n'avais pas regardé. J'ai lu une absence produite par le protocole et j'y ai vu une signature.
### Le phénomène réel, beaucoup plus étroit
```
HEAD objet PRÉSENT (juste après le PUT) → REFUSÉ HTTP 403 (aucun code MinIO)
HEAD objet ABSENT → 404 NoSuchKey ← correct
GET objet présent → 200 ← correct
--- un instant plus tard ---
HEAD #1..#5 → 200, 200, 200, 200, 200
```
**Un `HEAD` émis immédiatement après le `PUT` de la même clé peut rendre 403 une fois, puis réussir.** C'est une affaire de **temps**, pas de droit : la politique est la même dans les deux cas, et l'objet absent est correctement rapporté.
⚠ **Je n'ai pas la cause.** `server: cloudflare` est dans la chaîne, et une lecture juste après écriture à travers un CDN est un suspect naturel — mais c'est une hypothèse, pas un diagnostic. Le middleware CrowdSec (`kube-system-crowdsec@kubernetescrd`) est aussi sur cet ingress, et une rafale de 403 depuis mon poste pendant les essais du matin a pu déclencher une limitation ; ça expliquerait pourquoi le même geste échouait en série puis passe aujourd'hui.
### Ce que ça change pour la suite
L'issue reste ouverte mais **change de nature** : ce n'est plus « HEAD est bloqué », c'est « une lecture juste après écriture peut rendre un 403 isolé ». Le risque pour Kadans est faible — le dépôt n'enchaîne pas PUT puis HEAD — mais il est réel pour tout code qui voudrait vérifier son écriture dans la foulée : il verrait un refus de droit là où il n'y en a pas.
⚠ Et la leçon vaut plus que le défaut : **j'ai publié un diagnostic sur une absence qui appartenait à mon instrument**, exactement le piège que ce dépôt documente. La correction a coûté une commande.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Mesuré le 2026-09-07, avec les identifiants du compte de service
kadans-appLe même objet, les mêmes identifiants, deux chemins :
s3.arcodange.frPUT(déposer)GET(relire les octets)HEAD(relire l'en-tête)HEADd'un objet ABSENTDELETEPourquoi ce n'est ni MinIO ni la politique
Trois raisons, chacune suffisante :
AccessDenieddans un corps XML ; ici c'est un « Forbidden » nu, sans code S3.Le suspect est donc au bord : Traefik, une middleware, CrowdSec, ou ce qui se trouve devant. Ce n'est pas un défaut de la politique IAM, qui vient d'être vérifiée des deux côtés dans arcodange/kadans#1033.
Ce que ça coûte aujourd'hui, et ce que ça coûtera
Aujourd'hui : rien. Le dépôt de vidéos de Kadans n'utilise que
PUTetGET, et la relecture des octets fonctionne. Ce n'est pas un incident en cours.Demain, oui :
HEADest la façon normale et bon marché de demander « cet objet existe-t-il, et combien pèse-t-il ? » sans rapatrier les octets. Tout code qui sonderait l'existence d'une vidéo depuis le navigateur — une reprise de téléversement, une vérification avant affichage, un contrôle d'intégrité — tomberait sur un 403 qui accuserait la politique IAM, c'est-à-dire le mauvais coupable. C'est précisément le genre de faux coupable qui coûte une session entière.Ce que je n'ai pas vérifié
OPTIONS,POSTsur d'autres routes). ⚠ Le préflight CORS du magasin a son propre gate côté front (bun run check:cors) — à relire siOPTIONSétait concerné.🤖 Generated with Claude Code
⚠⚠ CORRECTION — cette issue était fausse sur deux points
Remesuré le 2026-09-08, avec les mêmes identifiants, en lisant cette fois les en-têtes de la réponse. Ce que j'avais écrit ne tient pas.
Ce que j'avais dit, et ce qui est vrai
200404avecx-minio-error-code: NoSuchKeyx-minio-error-codeetx-amz-request-id: c'est MinIO qui répondMon erreur de méthode est nette : une réponse à un
HEADn'a pas de corps, donc le XML d'erreur de S3 est absent et boto3 rapporte un « 403 Forbidden » nu. J'en ai conclu que l'erreur ne venait pas de S3. Le code d'erreur était dans un en-tête que je n'avais pas regardé. J'ai lu une absence produite par le protocole et j'y ai vu une signature.Le phénomène réel, beaucoup plus étroit
Un
HEADémis immédiatement après lePUTde la même clé peut rendre 403 une fois, puis réussir. C'est une affaire de temps, pas de droit : la politique est la même dans les deux cas, et l'objet absent est correctement rapporté.⚠ Je n'ai pas la cause.
server: cloudflareest dans la chaîne, et une lecture juste après écriture à travers un CDN est un suspect naturel — mais c'est une hypothèse, pas un diagnostic. Le middleware CrowdSec (kube-system-crowdsec@kubernetescrd) est aussi sur cet ingress, et une rafale de 403 depuis mon poste pendant les essais du matin a pu déclencher une limitation ; ça expliquerait pourquoi le même geste échouait en série puis passe aujourd'hui.Ce que ça change pour la suite
L'issue reste ouverte mais change de nature : ce n'est plus « HEAD est bloqué », c'est « une lecture juste après écriture peut rendre un 403 isolé ». Le risque pour Kadans est faible — le dépôt n'enchaîne pas PUT puis HEAD — mais il est réel pour tout code qui voudrait vérifier son écriture dans la foulée : il verrait un refus de droit là où il n'y en a pas.
⚠ Et la leçon vaut plus que le défaut : j'ai publié un diagnostic sur une absence qui appartenait à mon instrument, exactement le piège que ce dépôt documente. La correction a coûté une commande.
🤖 Generated with Claude Code