Aller au contenu principal
Lance-toi : 40% de réduction sur toutes les formations jusqu'au 30 juin En savoir plus

Least Privilege : le principe qui rend tes bugs et tes failles dix fois moins graves

Un token API qui peut tout faire alors qu'il sert à lire trois fichiers. Un utilisateur Postgres qui peut DROP la base alors qu'il ne fait que des SELECT. Un conteneur Docker qui tourne en root sans aucune raison. Le principe de moindre privilège existe pour transformer ces accidents en non-événements.

Architecture logicielle ·
Adel LATIBI
Adel LATIBI

Le Briefing Dev - les ressources et actus de la semaine, droit dans ta boîte chaque vendredi gratuitement.

Quand une faille de sécurité fait la une, l'attention va sur la vulnérabilité technique. Mais ce qui transforme une petite faille en désastre, c'est presque toujours autre chose : le compte compromis avait beaucoup trop de droits.

Toi, tu as déjà créé un utilisateur de base de données en deux secondes avec GRANT ALL parce que tu voulais finir la tâche avant la fin de la journée. Tu as déjà collé une clé AWS dans un script avec des permissions trop larges en te disant "je nettoierai plus tard". Tu as déjà installé un conteneur en lui donnant accès à --privileged parce que sinon ça ne fonctionnait pas. Et plus tard, ce qui devait être un petit incident est devenu un gros problème.

Le problème n'est pas le manque d'outils de sécurité. Les permissions fines existent partout : Linux, AWS, Postgres, Kubernetes, OAuth. Le problème est plus simple. Personne ne prend le temps de réfléchir aux droits minimum nécessaires. On donne trop par défaut, on retire jamais, et un jour quelqu'un exploite ce qu'on avait oublié.

Dans ce qui suit, tu vas voir d'où vient ce principe, à quoi il ressemble dans le code et l'infra que tu écris déjà, et comment l'appliquer sans tomber dans la paranoïa qui bloque les équipes pendant deux semaines sur un ticket.

Le problème, raconté avec un cas que tu reconnais

Une startup déploie son application en production. Un développeur crée un utilisateur Postgres pour l'API. Pressé, il tape GRANT ALL PRIVILEGES ON DATABASE prod TO api_user. Ça marche, l'application est en ligne, tout le monde passe à autre chose.

Six mois plus tard, une dépendance npm a une faille connue. Un attaquant exécute du SQL arbitraire à travers un endpoint mal protégé. Avec un utilisateur correctement limité, il aurait pu lire quelques lignes de la table users. Avec GRANT ALL, il DROP la base entière en une commande. Les backups existent, mais la dernière restauration cohérente date de trois jours. La perte est réelle.

Cette histoire se répète chaque semaine quelque part. Et le coupable n'est pas l'attaquant, il est juste opportuniste. Le coupable, c'est le GRANT ALL initial. Une décision prise en dix secondes qui a multiplié l'impact de la faille par mille.

Le coût d'avoir donné trop de droits est toujours invisible jusqu'au jour où il devient catastrophique. C'est exactement ce que le principe de moindre privilège cherche à neutraliser, en imposant une discipline à l'entrée plutôt que de courir après les dégâts à la sortie.

Le principe, dans sa formulation d'origine

Le Principle of Least Privilege, ou POLP, a été formulé par Jerome Saltzer et Michael Schroeder en 1975 dans un article de référence intitulé "The Protection of Information in Computer Systems". La règle tient en une phrase :

Le mot important, c'est "nécessaire". Pas "utile", pas "commode", pas "au cas où". Si un service lit des fichiers, il ne doit pas pouvoir en écrire. Si un utilisateur consulte des données, il ne doit pas pouvoir les modifier. Si un script tourne sur un seul dossier, il ne doit pas pouvoir accéder au reste du disque.

La conséquence pratique est puissante : quand une compromission arrive (et elle arrive toujours), l'attaquant hérite des droits du composant compromis. Si ces droits sont minimaux, le rayon d'action de l'attaque l'est aussi. C'est exactement la logique d'un compartiment étanche dans un bateau : une brèche dans un compartiment ne coule pas le navire entier.

POLP s'applique partout où il y a une notion de permission : utilisateurs système, comptes de base de données, rôles cloud, scopes OAuth, capabilities Kubernetes, tokens API, droits applicatifs en interne. Le principe est le même, seuls les outils changent.

Exemples concrets, avant et après

Cas 1 : utilisateur Postgres

La version paresseuse, celle qu'on voit partout en début de projet :

CREATE USER api_user WITH PASSWORD 'xxx';
GRANT ALL PRIVILEGES ON DATABASE prod TO api_user;

Cet utilisateur peut créer des tables, les supprimer, modifier la structure du schéma, lire toutes les données, en écrire, et même créer d'autres utilisateurs. L'API web, elle, n'a besoin que de SELECT, INSERT, UPDATE et DELETE sur quelques tables.

La version qui respecte POLP nomme explicitement ce que l'utilisateur peut faire :

CREATE USER api_user WITH PASSWORD 'xxx';
GRANT CONNECT ON DATABASE prod TO api_user;
GRANT USAGE ON SCHEMA public TO api_user;
GRANT SELECT, INSERT, UPDATE, DELETE
  ON users, orders, products
  TO api_user;

Si une injection SQL passe à travers la validation applicative, l'attaquant ne peut pas DROP TABLE, ne peut pas lire les tables sensibles non listées, ne peut pas modifier le schéma. Le rayon d'impact est réduit à ce que l'API fait déjà légitimement.

Cas 2 : conteneur Docker en root

Par défaut, un conteneur Docker tourne en root. Personne ne s'en rend compte parce que c'est isolé, mais le jour où une faille permet l'évasion du conteneur, l'attaquant débarque en root sur la machine hôte. Le Dockerfile paresseux ressemble à ça :

FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]

La version qui respecte POLP crée un utilisateur sans privilèges et bascule dessus avant de lancer l'application :

FROM node:20-alpine
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --chown=app:app . .
RUN npm install
USER app
CMD ["node", "server.js"]

Le processus tourne sous un utilisateur qui ne peut écrire que dans son propre dossier. Une compromission ne donne plus root, juste un compte ordinaire qui ne sait rien faire de plus. Si tu veux approfondir cette logique de durcissement des conteneurs, ça fait partie des sujets couverts dans la formation Docker pour développeurs web.

Cas 3 : token GitHub Actions trop bavard

Par défaut, le GITHUB_TOKEN d'un workflow a accès en lecture-écriture à tout le repo. Si ton workflow se contente de lire le code pour lancer des tests, tu peux restreindre le token au minimum :

name: CI
on: [push, pull_request]

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

Si une action tierce contient du code malveillant ou si une dépendance est compromise, le token ne peut rien faire d'autre que lire. Pas de push, pas de release, pas de modification des secrets. Cette même logique d'isolation rejoint la Separation of Concerns mais appliquée aux droits plutôt qu'au code.

Pourquoi ce principe change ta façon de concevoir une application

Le bénéfice premier de POLP n'est pas d'empêcher les attaques, c'est de limiter leur portée quand elles arrivent. Et elles arrivent. Une dépendance compromise, un employé qui se fait phisher, une clé API qui fuit dans un repo public, un développeur qui clique sur le mauvais lien. Tu ne peux pas garantir le zéro incident. Tu peux par contre garantir qu'un incident reste un incident, pas une catastrophe.

Le deuxième bénéfice est plus discret mais aussi important : POLP révèle ton architecture. Quand tu écris explicitement ce que chaque composant a le droit de faire, tu documentes son périmètre fonctionnel. Si tu te retrouves à donner trente permissions à un service, c'est probablement qu'il fait trop de choses, et qu'il aurait dû être découpé.

Le troisième bénéfice concerne les erreurs humaines. Un développeur qui se trompe d'environnement et lance un script de nettoyage en production ne supprime que ce que son compte a le droit de supprimer. Avec des comptes correctement scopés, ce genre d'incident reste embarrassant mais réparable.

Le quatrième bénéfice est réglementaire. RGPD, ISO 27001, SOC 2, HDS, toutes les normes de sécurité de l'information posent la question des accès. Pouvoir montrer que chaque utilisateur et chaque service a strictement ce dont il a besoin, et rien d'autre, simplifie énormément les audits.

Les pièges qui guettent quand tu appliques POLP

Piège 1 : tomber dans la paranoïa qui paralyse

Certaines équipes interprètent POLP comme une obligation de tout interdire par défaut et de demander chaque permission par ticket. Au bout de deux semaines, plus personne ne peut travailler, et les développeurs trouvent des contournements bien plus dangereux que l'excès de droits initial. L'objectif n'est pas de tout bloquer, c'est de calibrer ce qui est nécessaire.

La bonne posture : commencer large dans un environnement de développement, observer ce qui est réellement utilisé, restreindre au juste niveau avant de passer en staging et production. La friction reste raisonnable, la sécurité s'améliore là où ça compte.

Piège 2 : ne jamais réviser les droits accordés

POLP n'est pas un événement, c'est une habitude. Les besoins changent : un service qui ne faisait que lire commence à écrire, un développeur qui a quitté l'équipe garde son accès admin oublié, une fonctionnalité retirée laisse derrière elle des permissions inutiles. Sans revue régulière, les droits s'accumulent silencieusement et le principe est trahi par l'inertie.

Une revue trimestrielle des comptes humains et techniques est le minimum vital. Pour les comptes techniques, l'idéal est de générer la liste des permissions à partir du code (Terraform, Pulumi, fichiers de migration SQL versionnés), pour que toute modification soit tracée et revue.

Piège 3 : confondre POLP et Zero Trust

POLP et Zero Trust sont deux concepts complémentaires mais distincts. POLP dit "donne le minimum de droits". Zero Trust dit "vérifie chaque accès, même venant de l'intérieur du réseau". Tu peux appliquer POLP sans Zero Trust (les droits sont minimaux mais on fait confiance au réseau interne), et Zero Trust sans POLP (chaque accès est vérifié mais les comptes ont trop de droits).

Les deux ensemble forment une défense robuste. Mais commence par POLP, parce qu'il est plus facile à mettre en place et qu'il donne les premiers résultats en quelques semaines, là où Zero Trust demande une refonte plus profonde de l'infrastructure.

Piège 4 : oublier les permissions implicites

Donner SELECT sur une table semble inoffensif. Mais si cette table contient des e-mails de tous les clients, tu viens de donner accès à l'ensemble de la base utilisateur. Les permissions techniques ne reflètent pas toujours la sensibilité métier. Un audit de sécurité sérieux croise les deux dimensions.

La parade consiste à séparer les données sensibles dans des tables ou des schémas distincts, et à accorder les permissions au niveau granulaire (colonne, ligne via RLS en Postgres) plutôt qu'au niveau de la table entière. Ça demande plus de travail à la conception, ça en demande infiniment moins après un incident.

Piège 5 : croire que POLP ne concerne que le sysadmin

POLP s'applique aussi à l'intérieur du code applicatif. Une classe qui n'a besoin que d'un repository en lecture ne doit pas recevoir le repository complet. Une fonction qui n'a besoin que d'un champ utilisateur ne doit pas recevoir l'objet utilisateur entier. C'est le même principe, transposé au niveau du design objet.

Cette discipline rejoint d'autres principes que j'ai déjà couverts, comme la loi de Déméter qui limite ce qu'un objet a le droit de connaître de ses voisins. L'idée commune, c'est de réduire la surface d'interaction pour réduire la surface de bug.

Comment appliquer POLP dès cette semaine

La première étape consiste à dresser l'inventaire. Tu listes les comptes techniques (utilisateurs DB, rôles cloud, tokens API, comptes de service), et pour chacun tu écris en deux lignes ce qu'il fait réellement. Quand l'écart entre ce qu'il fait et ce qu'il a le droit de faire est béant, tu as identifié une cible prioritaire.

La deuxième étape, c'est le rattrapage progressif. Tu commences par les comptes les plus critiques : la base de production, les clés cloud qui peuvent provisionner des ressources, les tokens des outils de CI/CD. Tu ne touches pas à tout en même temps, tu corriges un compte par sprint, en testant en staging avant.

La troisième étape concerne les nouveaux comptes. Tu poses une règle simple dans l'équipe : aucun compte ne se crée avec des droits par défaut, on écrit toujours les permissions minimales explicitement, et on les versionne dans le code. Cette discipline simple stoppe l'accumulation à la source.

La quatrième étape, c'est l'outillage. AWS IAM Access Analyzer, GCP Policy Analyzer, les outils de détection de permissions sur-allouées dans Kubernetes (kubectl auth can-i), les scans Docker (Trivy, Snyk) intégrés à la CI font remonter automatiquement les écarts. Tu n'as pas à tout faire à la main, à condition d'avoir branché les bons outils. Le sujet est aussi traité dans la formation CI/CD avec GitHub Actions, qui couvre l'intégration de ces vérifications dans tes pipelines.

La cinquième étape, c'est la culture. Tu refuses en revue de code les pull requests qui élargissent des droits sans justification. Tu poses la question "pourquoi ce service aurait besoin de ce droit ?" à chaque ajout de permission. Au bout de quelques mois, l'équipe développe un réflexe, et POLP devient une exigence partagée plutôt qu'une lutte solitaire.

Ce que POLP dit vraiment de ton rapport au risque

Le principe de moindre privilège demande un effort de conception là où l'absence de principe demande zéro effort. C'est ce qui le rend impopulaire à court terme. Mais le calcul change dès qu'on intègre la probabilité d'incident sur la durée de vie d'une application.

Sur cinq ans, une application va voir passer des dizaines de dépendances compromises, plusieurs vulnérabilités CVE, au moins un cas de fuite de secrets, et plusieurs développeurs qui ne sont plus dans l'équipe. La question n'est pas "est-ce que ça va arriver", la question est "quand ça arrive, est-ce que ça reste réparable ou est-ce qu'on appelle un avocat ?".

POLP est ce qui fait la différence entre les deux scénarios. Pas un outil magique, juste une discipline qui consiste à donner moins par défaut et à expliquer pourquoi on donne quand on donne. Une fois que cette discipline est intégrée, tu ne reviens jamais en arrière, parce que tu vois soudain partout les portes qui n'avaient aucune raison d'être ouvertes.

Questions fréquentes

Le principe de moindre privilège, c'est uniquement pour la sécurité ?

Non. POLP réduit aussi l'impact des erreurs humaines, simplifie les audits réglementaires, et révèle des défauts d'architecture quand un composant accumule trop de droits. La sécurité est l'angle le plus connu mais pas le seul.

Comment savoir si un compte a trop de droits ?

Compare la liste des permissions accordées avec la liste des opérations réellement effectuées sur les trente derniers jours. Les logs de ta base, de ton cloud ou de ton orchestrateur te donnent cette information. Tout ce qui n'a pas été utilisé est candidat à la suppression.

POLP s'applique-t-il aussi au code applicatif ?

Oui. Une fonction ne devrait recevoir que les arguments dont elle a besoin, une classe ne devrait dépendre que des interfaces qu'elle utilise, un module ne devrait exposer que ce qui est nécessaire à ses consommateurs. C'est la même logique que côté infrastructure, appliquée à la structure du code.

Faut-il appliquer POLP dès le début d'un projet ou plus tard ?

Plus c'est tôt, plus c'est simple. Mettre des permissions strictes sur un projet à dix mille lignes est facile. Le faire sur un projet à un million de lignes prend des mois et casse des intégrations qu'on avait oubliées. Si le projet existe déjà, commence par les comptes critiques et progresse par lots.

Quelle différence entre POLP et le principe de séparation des privilèges ?

POLP dit qu'un acteur ne doit avoir que les droits dont il a besoin. La séparation des privilèges va plus loin : aucune action sensible ne doit pouvoir être effectuée par un seul acteur. C'est le principe du double clic en virement bancaire ou des deux paires d'yeux en revue de code. Les deux principes se complètent souvent.

Existe-t-il des outils pour automatiser l'application de POLP ?

Plusieurs. AWS IAM Access Analyzer détecte les politiques trop permissives, GCP Policy Analyzer fait la même chose côté Google, Open Policy Agent permet d'écrire des règles de permissions versionnées, et des outils comme Trivy ou Snyk analysent les images Docker pour détecter les conteneurs root. Aucun de ces outils ne dispense de la réflexion humaine sur ce qui est nécessaire.

Vous êtes expert ?

Partagez votre expertise sur notre blog

Tutoriel, retour d'expérience, analyse — publiez un article invité et gagnez en visibilité.

Écrire pour nous