veza/veza-backend-api/docs/CLAMAV_SETUP.md
senke 62f4ae2c82 fix(backend): require ClamAV in production environment
Add validation in ValidateForEnvironment() to fail startup when
CLAMAV_REQUIRED=false in production. Virus scanning is mandatory
for all file uploads in production.
Phase 1 audit - P1.4
2026-02-15 15:54:58 +01:00

238 lines
7 KiB
Markdown

# ClamAV Configuration — Veza Backend API
## Vue d'ensemble
Le backend Veza API intègre **ClamAV** pour scanner tous les fichiers uploadés avant toute persistance (base de données, système de fichiers, ou stockage S3). Cette fonctionnalité garantit qu'aucun malware ne peut être stocké sur le serveur.
**MOD-P1-001**: Le scan ClamAV est maintenant **obligatoire** et se fait **AVANT toute persistance**. Si ClamAV est indisponible, tous les uploads sont rejetés (fail-secure).
### Implémentation (clamdscan exec)
Le scan utilise **clamdscan** (exécutable système) au lieu de la bibliothèque go-clamd abandonnée. Aucune dépendance Go externe pour ClamAV. Le daemon clamd doit être démarré ; clamdscan s'y connecte via socket Unix ou TCP selon la configuration système.
---
## Variables d'environnement
### Configuration ClamAV
```bash
# Activer/désactiver ClamAV (par défaut: true)
CLAMAV_ENABLED=true
# Chemin vers clamdscan (par défaut: clamdscan)
# Ex: clamdscan, /usr/bin/clamdscan
CLAMAV_CLAMD_PATH=clamdscan
```
### Exemples de configuration
#### Développement local
```bash
CLAMAV_ENABLED=true
CLAMAV_CLAMD_PATH=clamdscan
```
#### Production (clamd sur machine distante)
Configurer clamd.conf pour pointer vers le daemon distant, ou utiliser un wrapper. Par défaut clamdscan utilise le socket Unix local.
#### Désactiver ClamAV (non recommandé en production)
```bash
ENABLE_CLAMAV=false
```
#### Production : CLAMAV_REQUIRED obligatoire
En production (`APP_ENV=production`), `CLAMAV_REQUIRED=true` est **obligatoire**. Le démarrage de l'API échouera avec une erreur explicite si `CLAMAV_REQUIRED=false`. Le scan antivirus des uploads est une exigence de sécurité en production.
---
## Installation et démarrage de ClamAV
### Linux (Ubuntu/Debian)
```bash
# Installer ClamAV
sudo apt-get update
sudo apt-get install clamav clamav-daemon
# Démarrer le daemon
sudo systemctl start clamav-daemon
sudo systemctl enable clamav-daemon
# Mettre à jour les signatures de virus
sudo freshclam
```
### Docker
```bash
# Lancer ClamAV dans un conteneur Docker
docker run -d --name clamav \
-p 3310:3310 \
-v /var/lib/clamav:/var/lib/clamav \
clamav/clamav:latest
```
### macOS (Homebrew)
```bash
# Installer ClamAV
brew install clamav
# Démarrer le daemon
brew services start clamav
```
---
## Comportement fail-secure
### Si ClamAV est activé mais indisponible
-**Le serveur démarre** (pas de blocage au démarrage)
-**Tous les uploads sont rejetés** avec HTTP 503 (Service Unavailable)
- 📝 **Message d'erreur clair** : "Virus scanning service is temporarily unavailable"
### Si un virus est détecté
-**L'upload est rejeté** avec HTTP 422 (Unprocessable Entity)
- 📝 **Message d'erreur** : "File rejected: virus detected"
- 🔒 **Le fichier n'est JAMAIS persistant** (ni DB, ni FS, ni S3)
### Si le scan échoue (timeout, erreur de connexion)
-**L'upload est rejeté** avec HTTP 503 (Service Unavailable)
- 📝 **Message d'erreur** : "Virus scan failed"
- 🔒 **Fail-secure** : en cas de doute, on rejette
---
## Tests
### Tests unitaires (sans ClamAV requis)
```bash
# Exécuter tous les tests unitaires
go test ./internal/services -run TestUploadValidator -v
# Tests spécifiques
go test ./internal/services -run TestUploadValidator_ClamAVDown_RejectsUploads -v
go test ./internal/services -run TestUploadValidator_ClamAVDisabled_AllowsUploads -v
```
### Tests d'intégration (ClamAV requis)
Les tests d'intégration nécessitent ClamAV en cours d'exécution et utilisent un build tag.
```bash
# 1. Démarrer ClamAV (voir section Installation)
# 2. Exécuter les tests d'intégration avec le tag 'clamav'
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV -v
# 3. Test spécifique avec fichier EICAR (test virus standard)
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV_EICAR_Rejected -v
# 4. Test avec fichier propre
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV_CleanFile_Accepted -v
```
### Configuration pour les tests d'intégration
Par défaut, les tests utilisent `clamdscan`. Pour un chemin personnalisé :
```bash
export CLAMAV_CLAMD_PATH=/usr/bin/clamdscan
go test -tags=clamav ./internal/services -run TestUploadValidator_ClamAV -v
```
---
## Vérification que le scan se fait AVANT la persistance
### Preuve dans le code
1. **Handler** (`internal/core/track/handler.go:117-160`):
- Le scan ClamAV est appelé **AVANT** `trackService.UploadTrack()`
- Si le scan échoue, la fonction retourne immédiatement (pas d'appel au service)
2. **Service** (`internal/core/track/service.go:145-216`):
- `UploadTrack()` sauvegarde le fichier (ligne 182) et crée l'enregistrement DB (ligne 213)
- **Ces opérations ne sont jamais appelées** si le scan échoue dans le handler
3. **Validateur** (`internal/services/upload_validator.go:124-222`):
- `ValidateFile()` fait le scan ClamAV **avant** de retourner `result.Valid = true`
- Si le scan détecte un virus, `result.Valid = false` et une erreur est retournée
### Ordre d'exécution garanti
```
1. Handler reçoit le fichier uploadé
2. Handler appelle ValidateFile() avec context
3. ValidateFile() fait le scan ClamAV (timeout 30s)
4. Si scan OK → ValidateFile() retourne result.Valid = true
5. Si scan OK → Handler appelle trackService.UploadTrack()
6. UploadTrack() sauvegarde le fichier et crée l'enregistrement DB
```
**Si le scan échoue à l'étape 3, les étapes 5-6 ne sont JAMAIS exécutées.**
---
## Timeouts et limites
- **Timeout de scan** : 30 secondes maximum
- **Gestion du contexte** : Utilise `context.WithTimeout()` pour éviter les blocages
- **Logs structurés** : Tous les scans sont loggés avec `zap.Logger`
---
## Codes HTTP retournés
| Situation | Code HTTP | Message |
|-----------|-----------|---------|
| ClamAV indisponible (enabled mais down) | 503 | "Virus scanning service is temporarily unavailable" |
| Virus détecté | 422 | "File rejected: virus detected" |
| Erreur de scan (timeout, connexion) | 503 | "Virus scan failed" |
| Fichier propre | 201 | Upload réussi |
---
## Dépannage
### Le serveur démarre mais les uploads sont rejetés
**Symptôme** : HTTP 503 avec message "Virus scanning service is temporarily unavailable"
**Causes possibles** :
1. ClamAV n'est pas démarré : `sudo systemctl status clamav-daemon`
2. clamdscan introuvable : Vérifier `CLAMAV_CLAMD_PATH` et que clamd est installé
3. Firewall bloque le port 3310
**Solution** :
```bash
# Vérifier que ClamAV écoute
sudo netstat -tlnp | grep 3310
# Tester la connexion
telnet localhost 3310
# Redémarrer ClamAV
sudo systemctl restart clamav-daemon
```
### Les tests d'intégration échouent
**Symptôme** : `go test -tags=clamav` échoue avec erreur de connexion
**Solution** :
1. Vérifier que ClamAV est démarré
2. Vérifier que clamd est démarré et que clamdscan peut s'y connecter
3. Vérifier les logs : `sudo journalctl -u clamav-daemon -f`
---
## Références
- [ClamAV Documentation](https://docs.clamav.net/)
- [EICAR Test File](https://en.wikipedia.org/wiki/EICAR_test_file)