docs: upgrade Gitea 1.25.4 -> 1.27.3 + leçon sur appDefinitions/update
- Backup complet (dump SQL + volume) avant upgrade - Documente l'incident secondaire (502 temporaire sur git.sans.pub) causé par un payload appDefinitions/update incomplet ayant réinitialisé containerHttpPort à sa valeur par défaut, et le correctif appliqué - Ajoute un avertissement dans CLAUDE.md : cette API remplace la config, ne la fusionne pas Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
66c356848b
commit
2e0ae9a91c
@@ -93,9 +93,11 @@ Endpoints utiles :
|
||||
- `GET /user/apps/appDefinitions` → liste toutes les apps avec `envVars`, `volumes`, `ports`, etc.
|
||||
- `POST /user/apps/appDefinitions/update` (payload : `appName` + les champs à conserver/modifier) → met à jour la config d'une app **sans redéployer l'image** (mais redémarre le service)
|
||||
|
||||
⚠️ **`appDefinitions/update` remplace, ne fusionne pas** : un champ absent du payload est réinitialisé à sa valeur par défaut (vécu en prod le 2026-09-23 : `containerHttpPort` oublié → réinitialisé à `80` au lieu de `3000` → 502 sur git.sans.pub pendant plusieurs minutes, cf `incidents/2026-09-14-gitea-cryptominer.md`). **Toujours faire un `GET /user/apps/appDefinitions` juste avant et renvoyer l'objet complet**, en ne modifiant que le(s) champ(s) voulu(s).
|
||||
|
||||
## Gitea — détails techniques
|
||||
|
||||
- **Containers Docker** (Swarm) : `srv-captain--gitea.1.*` (gitea/gitea:1.25.4) + `srv-captain--gitea-db.1.*` (mysql:5.7)
|
||||
- **Containers Docker** (Swarm) : `srv-captain--gitea.1.*` (gitea/gitea:1.27.3, mis à jour le 2026-09-23) + `srv-captain--gitea-db.1.*` (mysql:5.7)
|
||||
- **Volume de données** : `captain--gitea-data` → monté sur `/data` dans le container
|
||||
- Dépôts bare : `/data/git/repositories/<owner>/<repo>.git`
|
||||
- Config app : `/data/gitea/conf/app.ini` (contient des secrets en clair : `INTERNAL_TOKEN`, `LFS_JWT_SECRET`, mot de passe MySQL — jamais versionner ce fichier)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Incident : mineur de cryptomonnaie via Gitea (packObjectsHook)
|
||||
|
||||
- **Statut** : contenu, secrets serveur rotés (2026-09-23). Reste : upgrade Gitea, restriction `/api/internal/*`, mots de passe utilisateurs/tokens/webhooks.
|
||||
- **Statut** : contenu, secrets serveur rotés et Gitea mis à jour vers 1.27.3 (2026-09-23). Reste : restriction `/api/internal/*`, mots de passe utilisateurs/tokens/webhooks.
|
||||
- **Date de compromission** : 2026-09-14 ~15:16-15:17
|
||||
- **Date de détection** : 2026-09-22 (via un `git clone` cassé)
|
||||
- **Impact** : exécution de code sur le serveur hébergeant Gitea (et potentiellement l'hôte partagé, ~40 services CapRover) ; minage de cryptomonnaie (Monero) actif pendant ~8 jours
|
||||
@@ -88,9 +88,23 @@ Effectué :
|
||||
|
||||
Outillage utilisé : CLI `caprover` (installé localement via `fnm` + `npm install -g caprover`, authentifié avec `caprover login` — voir section CapRover CLI dans `CLAUDE.md`).
|
||||
|
||||
## Mise à jour Gitea 1.25.4 → 1.27.3 — effectuée le 2026-09-23
|
||||
|
||||
Corrige 15 advisories de sécurité publiées le 2026-08-29 (dont au moins 2 RCE en sévérité haute : bypass d'approbation sur les runners self-hosted, RCE via rendu externe de markup). Aucune ne correspond exactement au vecteur de cet incident (API interne), mais l'upgrade était largement justifiée.
|
||||
|
||||
Effectué :
|
||||
- [x] Backup complet avant upgrade : dump SQL (`mysqldump`, 114 tables) + tarball du volume de données complet (2,1 Go), dans `/home/zuck/backups/gitea-upgrade-20260923005619/` sur le serveur
|
||||
- [x] Déploiement de `gitea/gitea:1.27.3` via l'API CapRover (`POST /user/apps/appData/gitea` avec `captainDefinitionContent`)
|
||||
- [x] Démarrage vérifié sans erreur de migration, `Git version: 2.54.0`
|
||||
|
||||
### Incident secondaire causé pendant l'upgrade (auto-résolu le jour même)
|
||||
|
||||
La mise à jour CapRover de `DB_PASSWD` faite plus tôt (rotation des secrets, cf section dédiée) avait été envoyée avec un payload **incomplet** — le champ `containerHttpPort` n'était pas inclus. CapRover l'a réinitialisé à sa valeur par défaut (`80`) au lieu de conserver `3000` (le port réel utilisé par l'image officielle Gitea). Conséquence : **`git.sans.pub` a répondu en 502 pendant plusieurs minutes** (visible dans les logs nginx avec du trafic réel externe), le temps de diagnostiquer (`connect() failed (111: Connection refused)` vers `10.0.1.x:80`) et de renvoyer un payload complet avec `containerHttpPort: 3000` restauré.
|
||||
|
||||
**Leçon** : toute mise à jour via `POST /user/apps/appDefinitions/update` doit **toujours renvoyer l'intégralité des champs de la définition actuelle** (récupérés via un `GET /user/apps/appDefinitions` juste avant), pas seulement le(s) champ(s) qu'on veut changer — l'API ne fait pas de merge partiel, elle remplace.
|
||||
|
||||
## Reste à faire
|
||||
|
||||
- [ ] Mettre à jour Gitea vers la dernière version patchée (partir de `1.25.4`)
|
||||
- [ ] Vérifier/restreindre l'accès à `/api/internal/*` au niveau du reverse-proxy (défense en profondeur, même si Gitea patch le bug)
|
||||
- [ ] Changer les mots de passe des 3 comptes Gitea (pierre, Sans.pub, Duogeeks) par précaution
|
||||
- [ ] Révoquer et régénérer les 4 tokens d'accès personnels (LML, Piaire CI/Deploy, Piaire, Laptop .npmrc) — penser à mettre à jour partout où ils sont utilisés
|
||||
|
||||
Reference in New Issue
Block a user