From 92a5d37090e44f65a4dfd98866fdb093bb8d3323 Mon Sep 17 00:00:00 2001 From: bolbol Date: Thu, 9 Jul 2026 17:16:12 +0000 Subject: [PATCH] mcp-nas security audit: manche 3 (redaction audit.log deployee, scrub historique, token Gitea scope, astuce git/SMB) --- common/mcp-nas-security-audit.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/common/mcp-nas-security-audit.md b/common/mcp-nas-security-audit.md index fc1e896..a571090 100644 --- a/common/mcp-nas-security-audit.md +++ b/common/mcp-nas-security-audit.md @@ -3,7 +3,7 @@ **Tags** : infra, securite, mcp-nas, rce, docker-socket, secrets, rotation **Périmètre** : conteneur `linux-mcp-nas` (`mcp-nas.nd.i234.me`, port hôte 3042→8000, réseau Docker `n8n`). **Complète** : `common/audit-securite-reseau-nas-20260703.md` (couche réseau/WAN). Ici = **couche applicative**. -**Statut** : audit seul, correctifs **NON appliqués** (décision Nabil requise — rotation + coupure exposition = disruptif). +**Statut** (MàJ 2026-07-09) : **P0 fermés** (exposition anonyme, docker.sock, clés SSH Contabo) + **durcissement non-disruptif manche 3 fait** (rédaction audit.log, scrub historique, token Gitea scopé). **Reste** : rotation des credentials fuités (disruptif, à séquencer) + run non-root. Détail en bas. ## Verdict @@ -49,6 +49,30 @@ **Reste (non fait) :** P0 #3 (clés SSH Contabo hors conteneur + pwd sudo), P1 #4 (rédaction audit.log + **rotation credentials**), run non-root (`user:1026:100`), token Gitea repo-scopé. +## Manche 3 (2026-07-08) — durcissement non-disruptif FAIT et vérifié + +- **Rédaction audit.log DÉPLOYÉE.** `_redact` / `_SECRET_PATTERNS` ajoutés dans `linux_mcp_server.py` : masquage **à l'écriture** de `user:pass@` (URL), `Bearer`/`token `, `x-bf-vk`, `sshpass -p`, `echo '…' | sudo`, `<<< "…"` vers sudo, `curl -u user:pass`, `NOM…PASS/PWD/SECRET/TOKEN/KEY=…`, JSON `"password":…`. Testé en live (`curl -u bob:***`, `token ***` masqués). **N'affecte PAS l'exécution** (redaction sur la copie journalisée uniquement). → clôt P0 #5 / P1 #4 (volet rédaction). +- **audit.log HISTORIQUE scrubbé à 0.** Après scrub : famille `2L2u519w` = **0**, URLs `user:pass@` non masquées = 0, `x-bf-vk` / `Bearer` = 0. Méthode : one-off python (mêmes patterns + filet littéral via env `SCRUB_LITERAL_RE`), **remplacement d'inode** puis recréation du conteneur pour rouvrir le fd d'écriture. **Backup pré-scrub SUPPRIMÉ** (il contenait 278 mots de passe en clair). Temp `.claude-tmp` nettoyés. Fichier en `chmod 600 root:root`. +- **Token Gitea repo-scopé créé** (`mcp-nas-deploy`, scope `write:repository`) → `hermes-platform/.env` sous `GITEA_DEPLOY_TOKEN` (gitignoré). Vérifié : clone OK, API admin = 403 (bien limité). Remplace le **mot de passe `bolbol` complet** dans les URLs de clone/API. → clôt P1 (token scopé). +- **Versionné via API Gitea** : `linux_mcp_server.py` (commit `c4f3b2d`) + `docker-compose.yml` (`4094366`) sur `bolbol/linux-mcp-nas` main. + +### 🔑 Astuce git/SMB réutilisable (découverte) + +`git` sur le share SMB `/Volumes/docker` **hang** (timeouts ~2 min : le `.git` est sur SMB) **et git est absent de l'hôte NAS**. → **NE PAS** faire `git push` depuis le Mac sur ce share. À la place, pousser via l'**API HTTP Gitea `contents`** (aucun git requis, `curl` vers `gitea.bolbol.tn` répond vite) : + +```sh +TOK=$GITEA_DEPLOY_TOKEN # scope write:repository suffit pour contents API +# 1) récupérer le sha courant du fichier +SHA=$(curl -s -H "Authorization: token $TOK" \ + "https://gitea.bolbol.tn/api/v1/repos/OWNER/REPO/contents/PATH?ref=main" | jq -r .sha) +# 2) PUT le nouveau contenu (base64) avec le sha +curl -s -X PUT -H "Authorization: token $TOK" -H "Content-Type: application/json" \ + "https://gitea.bolbol.tn/api/v1/repos/OWNER/REPO/contents/PATH" \ + -d "{\"message\":\"msg\",\"content\":\"$(base64 -i FICHIER)\",\"sha\":\"$SHA\",\"branch\":\"main\"}" +``` + +Marche aussi depuis le conteneur mcp-nas (pas de git dedans). Pour créer un fichier neuf : même PUT **sans** `sha`. + ## Vérif rapide (depuis un poste externe) ```sh # Doit ÉCHOUER (401) — plus de RCE anonyme :