Skip to main content

Antivirus — détails techniques

Fiche fonctionnelle

Ce que le dispositif contrôle, les réglages de plateforme et leurs effets : Antivirus des pièces jointes.

Où l'analyse s'insère

Tous les modules déposent leurs pièces jointes par le même chemin, Storage#writeUploadFile d'entcore. L'analyse est branchée là, et une seule fois : elle couvre donc d'un coup l'espace documentaire, la messagerie, le casier, le formulaire, le cahier de textes, exercizer, workflowhub, le chat, la vidéo, les présences, les compétences…

L'ordre est ce qui compte : l'analyse a lieu avant l'acquittement de l'upload.

POST /workspace/document
└─ FileStorage.writeUploadFile
├─ écriture du fichier sur le stockage
├─ appel du service antivirus (clamd)
│ ├─ sain / ignoré / désactivé → 200 {_id, status: ok}
│ └─ infecté + mode bloquant → suppression du fichier
│ 400 {status: error, message: file.infected}
└─ suite du traitement du module

C'est ce qui distingue ce dispositif de l'antivirus historique d'ODE (cf. Infra), qui analysait après coup et se contentait de remplacer le contenu du fichier une fois celui-ci déjà accepté et référencé.

L'utilisateur voit le message file.infected (ou file.not.scanned si l'analyse n'a pas pu aboutir et que la plateforme est réglée pour refuser dans ce cas), traduit en français et en anglais.

Raccordement (ent-core.yaml)

Bloc file-system.antivirus du module infra, recopié dans la configuration partagée et donc lu par tous les modules. Seul le raccordement est ici — la politique est dans le service.

file-system:
path: ${BASE_PATH}/storage/
antivirus:
url: ${ANTIVIRUS_URL}
mode: ${ANTIVIRUS_MODE} # stream | path
failOnError: false
timeout: 35000

Modes stream et path

  • stream (défaut) : le contenu est poussé au service. Ne suppose aucun volume partagé, donc le seul mode viable en développement local et sur un stockage S3. Au-delà de 32 Mo le contenu est relayé sans être gardé en mémoire ; la quarantaine, qui a besoin du contenu, est alors sautée.
  • path : le service lit le fichier sur le volume de stockage, monté chez lui en lecture seule au même chemin. Rien ne transite sur le réseau, y compris pour une vidéo de 200 Mo, et la quarantaine fonctionne quelle que soit la taille. Exige antivirus.sharedStorage: true dans le chart ; le volume de stockage étant en ReadWriteOnce, le chart impose alors la co-localisation des deux pods.

failOnError

Service injoignable ou analyse en échec : par défaut l'upload passe — une panne du scanner ne doit pas mettre l'ENT à genoux — et l'incident est journalisé et compté. failOnError: true inverse le choix : refuser plutôt qu'accepter un fichier non analysé.

Déploiement

Le conteneur est déployé par le chart monolithe (helm/openent-monolithe/templates/antivirus.yaml) : un Deployment, un Service interne et un volume persistant. Ce volume compte : sans lui, chaque redémarrage retélécharge ~250 Mo de signatures et perd les compteurs.

clamd charge toute la base en mémoire — en dessous de ~2 Gi il est tué au chargement, d'où les ressources par défaut du chart (2 Gi demandés, 3 Gi en limite).

Diagnostic

L'image n'embarque pas curl : on interroge l'API avec bun, qui est présent.

AV=$(kubectl -n ent get pod -l app.kubernetes.io/component=antivirus -o name | head -1)

# état complet : moteur, base virale, politique, compteurs, dernières détections
kubectl -n ent exec $AV -- bun -e \
'fetch("http://127.0.0.1:3550/status").then(r=>r.text()).then(console.log)'

# le moteur détecte-t-il vraiment ? (fichier de test EICAR)
kubectl -n ent exec $AV -- bun -e \
'fetch("http://127.0.0.1:3550/selftest",{method:"POST"}).then(r=>r.text()).then(console.log)'

Le service n'est pas exposé publiquement : c'est un ClusterIP, joignable seulement depuis l'intérieur du cluster.

note

La signature EICAR ne se déclenche que sur le fichier de test exact (68 octets) ou sur ce fichier dans une archive. Concaténer EICAR à un gros fichier ne produit aucune détection : c'est le comportement de ClamAV, pas un défaut du dispositif. Pour un test réaliste sur un gros fichier, mettre EICAR dans un .zip.

Couverture de tests

Le client d'analyse est couvert par 6 tests unitaires (common/src/test/java/org/entcore/common/storage/OpenEntAntivirusClientTest.java d'entcore) : fichier sain non bloqué, fichier infecté bloqué, infecté non bloqué en détection seule, erreur du service non bloquante par défaut, service injoignable bloquant sous failOnError.

L'image du conteneur est validée à chaque publication par la chaîne d'intégration, qui exige que le fichier de test EICAR soit détecté dans l'image publiée — une image qui démarre sans rien analyser ne passe pas.

L'écran d'administration n'a pas encore de test e2e.

Conformité

Maillon de la chaîne qualitéRéférence
🎯 Fonctionnalités attenduesfiche fonctionnelle
🧪 Tests réalisésclient d'analyse : 6 tests unitaires ; image : test EICAR en intégration continue ; écran d'administration : aucun test e2e à ce jour
✅ Tests de conformitétableau de conformité

Voir aussi