waza : sécuriser les agents et l'exécution
Un agent IA mal configuré peut vider votre variable PATH ou lire votre fichier .ssh en une fraction de seconde. Le concept de waza sécurisé répond à cette menace d’exécution de code non fiable.
L’isolation des processus via les namespaces Linux et les cgroups est indispensable dès que vous automatisez des scripts tiers. Les fuites de secrets dans les environnements d’exécution ont augmenté de 40% dans les infrastructures cloud en 2023.
Après cette lecture, vous saurez configurer des environnements d’exécution restreints en Python pour vos agents sans compromettre votre machine hôte.
🛠️ Prérequis
Installation des outils nécessaires pour tester l’isolation :
- Python 3.12+ (indispensable pour le typage avancé)
- Linux Kernel 5.15+ (pour le support complet des namespaces)
- pip install waza-tools
📚 Comprendre waza sécurisé
Le principe de waza sécurisé repose sur la stratification des privilèges. Contrairement à Docker qui utilise des couches de fichiers complexes, waza cible l’isolation des syscalls via seccomp. On utilise les namespaces Linux pour isoler le réseau (net), les utilisateurs (user) et le système de fichiers (mnt).
Comparaison technique :
| Caractéristique | Docker | waza sécurisé |
|-----------------|---------|---------------|
| Isolation | Container | Processus |
| Overhead | Élevé | Faible |
| Surface d'attaque| Large | Réduite |
L’approche waza se rapproche de la philosophie CPython : minimiser l’interface exposée. En Python, cela signifie manipuler l’objet subprocess.Popen avec une attention extrême aux descripteurs de fichiers ouverts.
🐍 Le code — waza sécurisé
📖 Explication
Dans code_source, la boucle for key in self.allowed_keys est cruciale. Elle garantit que seul le contenu explicite de allowed_keys est injecté. L’assignation manuelle de PATH évite que l’agent ne cherche des exécutables malveillants dans /tmp ou ~/.local/bin.
L’utilisation de subprocess.run avec capture_output=True permet d’isoler les flux stdout et stderr. Cela évite que l’agent ne pollue les logs de l’application principale. Le paramètre timeout=30 est votre dernière ligne de défense contre les processus zombies.
Dans code_source_2, l’usage de TypedDict avec Final permet une vérification statique via mypy. Si un développeur tente de modifier la politique à l’exécution, l’outil de typage le signalera. C’est le principe de la programmation défensive appliquée à la configuration.
Documentation officielle Python
🔄 Second exemple
Anti-patterns et pièges
Le premier piège, et le plus fréquent, est l’utilisation de os.environ.copy(). En faisant cela, vous transférez l’intégralité de votre environnement hôte à l’agent. Si vous avez des variables AWS_SECRET_ACCESS_KEY ou DATABASE_URL chargées, l’agent y a accès. Un waza sécurisé exige une approche par liste blanche (allow-list) et non par liste noire (deny-list).
Le second piège concerne le paramètre shell=True dans subprocess.run. C’est une invitation à l’injection de commandes. Si l’agent peut manipuler une chaîne de caractères passée à la commande, il peut injecter des opérateurs comme ; rm -rf /. Utilisez toujours des listes d’arguments (['ls', '-l']) et jamais de chaînes brutes.
Le troisième piège est l’absence de limitation des ressources (cgroups). Un agent Python peut très facilement créer une boucle infinie ou allouer massivement de la mémoire, provoquant un Out-Of-Memory (OOM) killer sur l’hôte. Sans une limite RLIMIT_AS ou une gestion via cgroups, votre infrastructure est vulnérable à un déni de service interne.
Enfin, ne négligez pas le répertoire de travail (cwd). Par défaut, le processus hérite du répertoire courant. Si votre script tourne dans votre répertoire personnel, l’agent peut lire vos fichiers de configuration. Un waza sécurisé doit toujours forcer un cwd vers un répertoire temporaire et isolé, idéalement un tmpfs.
▶️ Exemple d’utilisation
Scénario : Exécution d’un script de calcul simple avec une politique restrictive.
from waza_lib import WazaEnvironment
# On n'autorise que la variable PATH
env = WazaEnvironment(allowed_env_keys=["PATH"])
try:
# On lance une commande simple
result = env.execute_agent(["echo", "Hello from secure agent"])
print(f"Sortie : {result.stdout.strip()}")
except Exception as e:
print(f"Échec : {e}")
Sortie : Hello from secure agent
🚀 Cas d’usage avancés
1. Exécution de plugins tiers : Intégrez des modules Python téléchargés dynamiquement en les exécutant via une instance de WazaEnvironment pour limiter leur accès au système de fichiers.
2. Pipeline CI/CD dynamique : Créez des environnements éphémères pour chaque test unitaire. Utilisez AgentPolicy pour définir des limites de mémoire strictes par étape de test.
3. Code Interpreter pour LLM : Lorsqu’un agent IA génère du code Python, utilisez le pattern WazaEnvironment pour exécuter ce code dans un conteneur de processus isolé, empêchant l’accès aux variables d’environnement de votre serveur d’inférence.
🐛 Erreurs courantes
⚠️ Fuite d'environnement
Copier tout l’environnement hôte vers l’agent.
subprocess.run(cmd, env=os.environ.copy())
subprocess.run(cmd, env=safe_dict)
⚠️ Injection de commande
Utiliser shell=True avec des entrées non filtrées.
subprocess.run(f"ls {user_input}", shell=True)
subprocess.run(["ls", user_input], shell=False)
⚠️ Absence de timeout
Laisser un agent tourner indéfiniment (DoS).
subprocess.run(cmd)
subprocess.run(cmd, timeout=30)
⚠️ Invisibilité du répertoire de travail
Ne pas spécifier de répertoire de travail sécurisé.
subprocess.run(cmd)
subprocess.run(cmd, cwd="/tmp/sandbox")
✅ Bonnes pratiques
Pour garantir un waza sécurisé, suivez ces règles de fer :
- Principe du moindre privilège : Ne donnez accès qu’aux variables d’environnement strictement nécessaires.
- Immuabilité des politiques : Utilisez
FinaletTypedDictpour vos configurations de sécurité. - Sanitisation du PATH : Redéfinissez toujours
PATHde manière explicite et minimale. - Isolation du répertoire de travail : Utilisez toujours
cwdvers un dossier dédié et nettoyé. - Gestion du cycle de vie : Implémenteer systématiquement des
timeoutssur chaque appel de processus. - Audit des syscalls : Pour les environnements critiques, utilisez
straceouseccomppour vérifier l’absence d’appels interdits.
- L'héritage d'os.environ est la première cause de fuite de secrets.
- Le paramètre shell=True doit être banni de vos configurations d'agents.
- Un waza sécurisé nécessite une définition stricte du PATH.
- Le timeout est une protection indispensable contre les attaques DoS.
- L'utilisation de TypedDict permet de valider les politiques au moment du développement.
- L'isolation du répertoire de travail empêche la lecture de fichiers sensibles.
- La limitation des ressources (cgroups) prévient l'épuisement de la mémoire hôte.
- La sécurité doit être pensée au niveau de l'interface Python, pas seulement de l'OS.
❓ Questions fréquentes
Est-ce que waza sécurisé remplace Docker ?
Non. Docker est un outil de packaging et d’orchestration. Waza est une approche de sandboxing de processus pour l’exécution légère d’agents.
Puis-je utiliser waza avec des scripts Shell ?
Oui, mais évitez le shell=True. Passez les arguments sous forme de liste pour maintenir l’isolation.
Comment vérifier que mon environnement est réellement isolé ?
Utilisez l’outil `strace -p
Quel est l'impact sur les performances ?
L’impact est quasi nul, car nous ne créons pas de couches de fichiers supplémentaires, contrairement à Docker.
📚 Sur le même blog
🔗 Le même sujet sur nos autres blogs
📝 Conclusion
La sécurité de l’exécution d’agents ne dépend pas de la complexité de l’outil, mais de la rigueur de sa configuration. Un waza sécurisé repose sur une gestion granulaire des variables, du chemin de recherche et du temps d’exécution. Pour approfondir la gestion des processus en Python, consultez la documentation Python officielle. Une surveillance des appels système via strace reste le seul moyen de vérifier l’intégrité d’un waza sécurisé.