📍 Article principal : Deno 2 en production 2026
Introduction
Une équipe de cybersécurité d’une banque sénégalaise auditait en 2025 le code Node de son API publique et a recensé 487 dépendances transitives, dont 23 packages avec moins de 100 téléchargements par semaine. Ces packages obscurs représentent la surface d’attaque principale pour les attaques par chaîne d’approvisionnement. La migration de cette API vers Deno 2 a permis d’imposer un manifeste de permissions explicites au runtime, transformant chaque dépendance suspecte en simple morceau de logique sans capacité d’exfiltration. Ce tutoriel détaille pas-à-pas la maîtrise des permissions Deno : les six catégories essentielles, leurs flags spécifiques, les patterns de configuration en développement et en production, l’intégration avec systemd et Docker, et le processus d’audit qui valide qu’un programme respecte le principe du moindre privilège.
Prérequis
- Deno 2.0+ installé localement
- Connaissance de base de la ligne de commande Linux ou macOS
- Notions de sécurité applicative (bon à avoir, pas obligatoire)
- Niveau : intermédiaire — Temps : 1 h 30
Étape 1 — Les six catégories de permissions
Deno expose six catégories de permissions, chacune correspondant à une capacité système distincte. Comprendre ces catégories est la base pour ensuite construire des manifestes précis. La catégorie net contrôle l’accès réseau, qu’il s’agisse de bind un port en écoute (serveur HTTP) ou d’effectuer des fetch sortants vers des API tierces. La catégorie read autorise la lecture de fichiers et dossiers — par défaut tout le système de fichiers est inaccessible. La catégorie write couvre l’écriture, séparée de la lecture pour permettre des autorisations asymétriques (lire la config, écrire seulement dans logs). La catégorie env régit l’accès aux variables d’environnement, individuellement nommées si on veut être strict.
Les deux dernières catégories couvrent des opérations moins fréquentes. run autorise le lancement de sous-processus shell, comme git ou imagemagick — capacité dangereuse car un sous-processus peut faire tout ce que Deno ne lui interdit pas explicitement. ffi (Foreign Function Interface) autorise le chargement de bibliothèques natives compilées, encore plus puissant et donc à utiliser avec parcimonie. Pour 95 % des applications backend classiques, on n’a besoin que de net, read, et env — les trois autres restent désactivées.
Étape 2 — Syntaxe et granularité
Chaque flag de permission accepte une liste de valeurs spécifiques séparées par virgules. Cette granularité est essentielle pour appliquer le principe du moindre privilège. Pour –allow-net, on précise les hôtes autorisés : --allow-net=api.wave.com,api.example.sn,localhost:5432. Sans cette précision, on autorise tout le réseau, ce qui annule largement le bénéfice. Pour –allow-read, on précise les chemins : --allow-read=./config,./public,./uploads. Pour –allow-env, on liste les noms : --allow-env=DATABASE_URL,JWT_SECRET,NODE_ENV.
deno run \
--allow-net=api.example.sn,db.internal:5432 \
--allow-read=./config,./public \
--allow-write=./logs \
--allow-env=DATABASE_URL,JWT_SECRET,STRIPE_KEY \
server.ts
Cette commande illustre un manifeste minimaliste pour un serveur HTTP qui appelle deux API externes, lit ses fichiers de configuration et publics, écrit ses logs, et utilise trois variables d’environnement. Toute tentative de lecture en dehors de ces chemins, tout fetch vers un autre domaine, toute lecture d’une variable non listée déclenche immédiatement une erreur PermissionDenied visible dans les logs.
Étape 3 — Permissions en développement vs production
En développement local, on accepte parfois des permissions plus larges pour fluidifier l’expérimentation. Le flag --allow-all (alias -A) autorise tout sans restriction — pratique pour explorer une nouvelle bibliothèque sans se poser la question des permissions exactes nécessaires. La discipline pratique est cependant de basculer vers un manifeste précis dès qu’on entre en phase de stabilisation. Les fichiers deno.json à la racine du projet permettent de définir des tasks avec leurs permissions, séparant développement et production.
// deno.json
{
"tasks": {
"dev": "deno run -A --watch server.ts",
"start": "deno run --allow-net=api.example.sn,db:5432 --allow-read=./config --allow-env=DATABASE_URL,JWT_SECRET server.ts",
"test": "deno test --allow-net=localhost --allow-read=./tests"
}
}
Avec cette structure, deno task dev donne toute liberté pour le développement, deno task start reproduit la configuration de production, et deno task test isole les tests dans un sandbox approprié. Cette séparation par task documente naturellement les permissions requises et facilite l’audit ultérieur.
Étape 4 — Configuration systemd en production
Pour un serveur Deno déployé sur un VPS Hetzner via systemd, les permissions vivent dans le fichier de service. Cette approche centralise les permissions et évite qu’elles soient modifiées accidentellement par un développeur dans le code applicatif. Le service systemd lance Deno avec les flags appropriés et systemd lui-même applique des restrictions supplémentaires au niveau OS.
[Service]
Type=simple
User=deno
WorkingDirectory=/srv/api
Environment=DATABASE_URL=postgresql://...
Environment=JWT_SECRET=...
ExecStart=/usr/local/bin/deno run \
--allow-net=db.internal:5432,api.wave.com \
--allow-read=/srv/api/config,/srv/api/public \
--allow-write=/srv/api/logs \
--allow-env=DATABASE_URL,JWT_SECRET \
/srv/api/server.ts
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/srv/api/logs
Les directives systemd NoNewPrivileges, PrivateTmp, et ProtectSystem=strict ajoutent une couche de défense au niveau du noyau Linux. Même si une vulnérabilité dans Deno permettait de contourner les permissions runtime, le processus reste contraint par le kernel. Cette défense en profondeur est particulièrement importante pour les services exposés publiquement comme une API SaaS.
Étape 5 — Docker et permissions
Pour les déploiements en conteneur, Deno fournit une image Docker officielle denoland/deno. La configuration combine les permissions Deno classiques avec les bonnes pratiques de containerisation : utilisateur non-root, capacités Linux réduites, filesystem en read-only sauf volumes spécifiques.
FROM denoland/deno:2.0.6
WORKDIR /app
COPY deno.json deno.lock ./
RUN deno install --frozen
COPY . .
USER deno
EXPOSE 3000
CMD ["run", "--allow-net=0.0.0.0:3000,db:5432", "--allow-read=./config", "--allow-env=DATABASE_URL", "server.ts"]
Pour Cloudflare Workers ou Deno Deploy, les permissions sont gérées différemment : la sandbox du runtime impose ses propres restrictions, et certaines permissions (run, ffi) sont indisponibles par construction. Cette contrainte de plateforme renforce la sécurité par défaut sans configuration supplémentaire. Pour les SaaS qui ciblent le edge, c’est un avantage : moins de réflexion sur les permissions, plus de focus sur la logique métier.
Étape 6 — Audit et processus de revue
Pour les projets sensibles, on intègre une étape de revue des permissions dans le processus de PR. Toute modification du fichier deno.json ou du service systemd doit être justifiée et approuvée par un développeur senior. Cette discipline évite les « élargissements progressifs » qui finissent par redonner toutes les permissions au programme. Un script d’audit périodique compare les permissions accordées avec celles réellement utilisées par le code (via analyse statique des appels Deno.X).
L’outil deno info liste les modules importés par un script et leurs propres dépendances. Cette traçabilité facilite la vérification : un nouveau package qui apparait dans le graphe de dépendances peut être audité avant ajout. Pour les projets critiques, on peut figer les imports via deno install --frozen qui empêche toute modification non explicite. Cette protection contre les attaques par dépendance est complémentaire aux permissions runtime.
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| « Permission denied » sur fetch | Domaine non listé dans --allow-net |
Ajouter le domaine spécifique |
| Variables d’env vides | Manque --allow-env=NOM |
Lister explicitement chaque variable |
| Permissions changent à chaque commit | Pas de discipline de PR | Imposer revue des changements deno.json |
| Sous-processus refusé | Manque --allow-run |
Préciser commandes autorisées : --allow-run=git,curl |
| Performance dégradée vs Node | Permissions vérifiées à chaque appel | Surcoût négligeable en pratique < 1 ms |
Adaptation au contexte ouest-africain
Trois aspects pratiques. Premièrement, pour les projets fintech soumis aux exigences de conformité BCEAO et CIMA, le manifeste explicite des permissions Deno facilite considérablement l’audit de sécurité. Présenter aux auditeurs un fichier deno.json précis et un service systemd avec capacités limitées rassure plus qu’expliquer les multiples couches de configuration npm qui peuvent être contournées. Deuxièmement, pour les agences qui livrent des projets à des clients institutionnels (banques, compagnies d’assurance, ONG internationales), la sécurité par permissions est un argument commercial de plus en plus apprécié. Troisièmement, pour les juniors locaux qui apprennent le développement backend, internaliser dès le début la pensée par permissions développe une posture sécurité proactive qui sera utile tout au long de leur carrière, indépendamment du runtime utilisé.
Pour la formation interne d’une équipe à ces patterns, prévoir une à deux journées de pratique guidée. Les exercices typiques : prendre un script Node existant, le porter en Deno, déterminer le manifeste de permissions minimal qui le fait fonctionner, justifier chaque flag. Cette démarche révèle souvent des fonctionnalités du script dont on n’avait pas conscience (par exemple, une lecture de fichier dans /tmp oubliée), permettant de les évaluer à la lumière de la sécurité.
Tutoriels frères
Pour aller plus loin
- 🔝 Pilier : Deno 2 en production 2026
- Articles connexes : VPS hardening sécurité 2026
- Doc : Deno security model
FAQ
Les permissions Deno protègent-elles contre tous les types d’attaques ?
Non. Elles protègent contre l’exfiltration via réseau ou disque par une dépendance compromise. Elles ne protègent pas contre les bugs logiques de votre propre code (XSS, injection SQL via input utilisateur). La sécurité reste multi-couches.
Comment gérer un programme qui a vraiment besoin de toutes les permissions ?
Rare en pratique. Pour les outils CLI complexes ou les builders qui orchestrent plusieurs sous-processus, accepter -A est légitime. Pour les serveurs HTTP exposés, jamais.
Peut-on demander dynamiquement une permission au lancement ?
Deno supporte Deno.permissions.request() qui invite l’utilisateur via prompt en TTY. Utile pour les CLI interactives, inadapté aux serveurs.
Les permissions s’appliquent-elles aux modules importés ?
Oui, transitivement. Un module importé hérite des permissions du programme principal. Il ne peut pas en obtenir plus.
Patterns avancés et cas limites
Trois patterns avancés émergent dans les déploiements Deno mature. Le premier est la gestion des permissions dynamiques pour les serveurs multi-tenant. Quand chaque tenant peut configurer ses propres webhooks vers des URLs externes, on ne peut pas lister statiquement les domaines autorisés. La solution adoptée : un sous-processus Deno dédié à l’envoi des webhooks, avec un manifeste plus permissif (--allow-net sans liste), isolé du processus principal qui garde un sandbox strict. Cette séparation par sous-processus matérialise le principe de privilège minimal au niveau architectural.
Le deuxième pattern est l’audit automatique en CI. Un script de vérification compare les permissions déclarées dans deno.json avec celles requises par l’analyse statique du code (greps sur Deno.readFile, fetch, etc.). Toute divergence — permission accordée mais non utilisée, ou utilisation détectée mais permission manquante — fait échouer la PR. Cette discipline empêche la dérive progressive vers des permissions excessives. Quelques équipes ouest-africaines mature ont implémenté ce pattern et rapportent une réduction nette des incidents de sécurité liés aux dépendances.
Le troisième pattern est la rotation des secrets sans redéploiement. Avec systemd, les variables d’environnement sont chargées au démarrage du service. Pour rotationner un secret sans downtime, on utilise un fichier EnvironmentFile que systemd recharge sur systemctl reload (avec un handler SIGHUP côté Deno). Combiné aux permissions strictes sur ce fichier (lecture root uniquement), cette approche permet de tourner les secrets à intervalles courts sans interruption de service.
Sécurité Deno vs Node vs Bun
Pour situer Deno dans le paysage 2026, comparons les trois runtimes sur leur posture de sécurité native. Node 22 n’impose aucune restriction par défaut : un script Node peut lire tout le disque, accéder à tout le réseau, exécuter n’importe quel sous-processus. La sécurité repose entièrement sur le code applicatif et les conventions d’écosystème. Bun 1.2 hérite de la philosophie Node sans restrictions runtime, mais propose un système de « trusted dependencies » qui limite les postinstall scripts — défense partielle contre une classe spécifique d’attaques. Deno 2 est le seul à imposer un sandbox actif par défaut, avec permissions explicites granulaires. Pour les workloads où la sécurité prime, Deno offre la posture la plus solide sans configuration tierce.
Cas d’étude : prévenir un incident de chaîne d’approvisionnement
En octobre 2024, le package npm ua-parser-js avait fait l’objet d’une compromission temporaire où une version malveillante exfiltrait des données vers un serveur tiers. Cet incident, rapporté publiquement, illustre exactement le type d’attaque que les permissions Deno neutralisent. Une équipe utilisant ce package en Node sans surveillance était exposée pendant la fenêtre d’incident — le code malveillant pouvait exfiltrer variables d’environnement, secrets, fichiers de configuration vers le domaine de l’attaquant. La même équipe en Deno avec --allow-net=api.example.sn bloquait automatiquement la tentative d’exfiltration : le fetch vers le domaine tiers déclenchait une PermissionDenied immédiate, l’exfiltration échouait, l’incident s’arrêtait là.
Pour les SaaS ouest-africains qui traitent des données sensibles (KYC fintech, dossiers médicaux santé numérique, données PII), ce niveau de protection vaut largement l’effort de configuration initial. Documenter cet argument dans le dossier de conformité présenté aux régulateurs (BCEAO, CIMA, autorité de protection des données du pays) renforce la crédibilité technique de la structure. Plusieurs régulateurs commencent en 2026 à demander explicitement comment la posture sécurité est garantie face aux risques de chaîne d’approvisionnement, et présenter un manifeste Deno précis répond directement à cette préoccupation.