Aller au contenu

Durcir les postes de développeurs contre le vol de code et secrets

Durcir les postes de développeurs contre le vol de code et secrets

Section intitulée « Durcir les postes de développeurs contre le vol de code et secrets »

Le poste de développement est un concentrateur de privilèges : dépôt Git, jetons d’accès, clés privées, accès au cloud, outils d’administration et parfois données de production y cohabitent. Le compromis central est brutal : réduire la liberté locale ralentit certains usages, mais laisser un poste riche en secrets sans contrôle transforme chaque extension d’éditeur en candidat à l’incident majeur.

→ Lire l’explication complète de la marmotte

Poste de développement : une frontière de sécurité, pas un terminal personnel

Section intitulée « Poste de développement : une frontière de sécurité, pas un terminal personnel »

Le poste de développement doit être considéré comme un actif d’administration à privilèges, pas comme un poste bureautique avec un éditeur de texte un peu nerveux. Il héberge souvent des jetons Git, des identifiants de registre de conteneurs, des clés Secure Shell (SSH), des profils de fournisseur cloud et des sessions de navigateur vers des consoles d’administration. La compromission d’un seul poste peut donc produire une chaîne complète : vol du code, injection dans la chaîne CI/CD (Continuous Integration/Continuous Delivery), extraction de secrets, puis déploiement frauduleux.

La recommandation est de séparer trois niveaux d’usage :

  1. un poste bureautique sans accès direct aux environnements sensibles ;
  2. un poste de développement administré, destiné au code et aux outils de build ;
  3. une station d’administration renforcée pour les accès de production, les consoles cloud et les opérations d’urgence.

Fusionner ces usages dans une même machine réduit les coûts visibles et multiplie les chemins de compromission. Un navigateur ayant ouvert une pièce jointe douteuse ne doit pas pouvoir signer une image de conteneur ou pousser une modification d’infrastructure. La slide vendor appelle cela « convergence de l’espace de travail ». Un attaquant appelle cela « réduction du nombre d’étapes ».

Cette séparation n’impose pas trois ordinateurs physiques dans tous les cas. Une machine administrée avec des environnements isolés peut suffire, à condition que les frontières soient réelles : comptes distincts, secrets non partagés, politiques de périphériques séparées et absence de montage direct des répertoires sensibles dans l’environnement le moins fiable.

Les accès à privilèges doivent reposer sur une identité nominative fédérée. L’authentification multifacteur réduit le risque de réutilisation de mot de passe, mais ne protège pas contre le vol d’une session de navigateur active ni contre un jeton d’accès stocké localement. Les enjeux de fédération et de cycle de vie des identités relèvent directement de l’architecture des identités, pas d’un fichier README qui promet de ne jamais committer de secret.

Surface d’attaque : extensions, dépendances et sessions locales

Section intitulée « Surface d’attaque : extensions, dépendances et sessions locales »

L’éditeur de code est une plateforme d’exécution. Les extensions disposent fréquemment d’un accès aux fichiers du projet, au terminal intégré, aux variables d’environnement et parfois aux identifiants du gestionnaire de versions. Installer une extension revient à exécuter du code tiers dans le contexte où vivent les secrets. Une liste blanche d’extensions approuvées est donc préférable à une liberté totale avec détection a posteriori.

Les dépendances de développement constituent une autre voie d’entrée. Une attaque de confusion de dépendances consiste à publier un paquet public portant le nom d’une dépendance interne attendue par l’outil de build. Si le gestionnaire de paquets privilégie le registre public ou mélange les sources sans règle explicite, le code malveillant s’exécute pendant l’installation. Les scripts postinstall, les générateurs de code et les hooks Git méritent le même niveau de méfiance : ils exécutent du code local avec les droits de la session, ce qui est une définition assez honnête du problème.

Le verrouillage des versions par fichier de résolution réduit les surprises, mais ne garantit pas l’intégrité du paquet récupéré. Il faut exiger des sommes de contrôle, configurer un registre interne comme source autoritaire et auditer les paquets introduits. Les signatures de paquets ne corrigent pas un éditeur compromis ou une clé de signature volée. Elles prouvent l’origine déclarée d’un artefact, pas la bonté morale de son contenu. La cryptographie reste très mauvaise pour détecter les mauvaises idées signées correctement. Les mécanismes de confiance doivent suivre une gouvernance cryptographique explicite.

Le navigateur local mérite un traitement sévère. Les sessions vers Git, le cloud et les outils de tickets sont souvent protégées par des cookies ou des jetons de session. Un logiciel malveillant exécuté sous le même compte peut les voler, même si l’authentification multifacteur a été impeccable cinq minutes plus tôt. Isoler les accès d’administration dans un profil de navigateur dédié, supprimer les extensions non nécessaires et imposer une réauthentification pour les opérations sensibles réduit cette exposition.

Les attaques physiques ne disparaissent pas parce que le parc est « full cloud ». Un démarrage externe, un périphérique USB émulant un clavier, un vol de machine déverrouillée ou une extraction du disque restent des scénarios réalistes. Le chiffrement complet du disque doit être lié au démarrage vérifié et à un module matériel de protection des clés. Il protège une machine éteinte, pas une session ouverte dans un café, dans un train ou dans l’inévitable salle de réunion où personne ne retrouve l’adaptateur vidéo.

Le système d’exploitation doit être pris en charge par l’outil de gestion de parc, recevoir ses correctifs automatiquement et appliquer une configuration déclarative. Une image de référence non gérée dérive vite : versions de compilateurs différentes, agents de sécurité absents, certificats importés à la main, puis diagnostic ésotérique à 23 heures. La reproductibilité n’est pas un luxe de plateforme, c’est une condition de sécurité.

Le socle minimal comprend :

  • chiffrement complet du disque avec démarrage vérifié et protection du chargeur d’amorçage ;
  • compte utilisateur sans privilèges administrateur permanents ;
  • élévation ponctuelle tracée, avec justification et durée limitée ;
  • pare-feu local entrant bloquant par défaut ;
  • protection contre les logiciels malveillants et détection comportementale administrées ;
  • inventaire des logiciels, des extensions et des versions de compilateurs ;
  • mises à jour du système, du navigateur, de l’éditeur et des outils de build ;
  • interdiction ou contrôle des supports amovibles ;
  • journalisation centralisée des événements de sécurité et d’authentification.

L’accès administrateur local ne doit pas être supprimé par principe religieux. Certains compilateurs, émulateurs ou pilotes exigent des privilèges. Il doit en revanche être temporaire, nominatif et journalisé. Un compte local partagé avec un mot de passe connu de l’équipe annule l’attribution des actions. L’attaquant apprécie ce type de patrimoine culturel.

Les environnements de développement en conteneur améliorent l’isolation des dépendances, mais ils ne protègent pas automatiquement l’hôte. Monter /var/run/docker.sock dans un conteneur donne généralement le contrôle du moteur de conteneurs et donc de l’hôte. Monter le répertoire personnel, les clés SSH ou le répertoire de configuration cloud dans chaque environnement annule la séparation promise. Un conteneur de développement doit recevoir uniquement les volumes et les jetons nécessaires à la tâche en cours.

Le réseau doit empêcher qu’un poste compromis atteigne librement les plans d’administration. Segmenter les accès aux registres, aux plateformes d’intégration et aux consoles internes limite le mouvement latéral. Un proxy sortant avec inspection des destinations, des règles de résolution de noms et une journalisation exploitable apporte plus de valeur qu’un réseau plat décoré d’un slogan zero trust. La publication et le filtrage réseau doivent être pensés avec les principes exposés dans la section réseaux.

Secrets locaux, clés de signature et accès aux dépôts

Section intitulée « Secrets locaux, clés de signature et accès aux dépôts »

Aucun secret de longue durée ne doit résider dans un fichier .env, un historique de shell ou un gestionnaire de mots de passe non administré. Les détecteurs de secrets dans les dépôts sont nécessaires, mais ils interviennent après l’écriture locale. Un jeton déjà présent dans l’historique Git doit être révoqué, pas seulement supprimé du dernier commit. Git conserve remarquablement bien les erreurs embarrassantes.

Les jetons d’accès personnel doivent être limités par dépôt, par environnement et par durée. Un jeton capable de lire tous les dépôts, pousser sur la branche principale et administrer les clés de déploiement est une délégation d’administration déguisée en confort. Préférer des jetons à durée courte émis par fédération, avec audience et permissions minimales. Lorsque le fournisseur ne permet pas cette granularité, compenser par des comptes de service dédiés et des contrôles réseau.

Les clés de signature doivent être séparées des clés SSH d’accès aux dépôts. Une clé SSH prouve l’accès à un service, une clé de signature atteste l’origine d’un artefact ou d’un commit selon le mécanisme choisi. Mélanger les usages complique la révocation et étend inutilement les conséquences d’une fuite. Les clés de signature à fort impact doivent rester dans un module matériel ou dans un service distant contrôlé, jamais dans un répertoire synchronisé par un outil de sauvegarde personnel.

La rotation doit être planifiée avant l’incident. Pour chaque secret, documenter le propriétaire, le système émetteur, les droits associés, la date d’expiration, le mécanisme de révocation et la procédure de remplacement. Une rotation sans dépendances cartographiées casse les builds. Une absence de rotation laisse l’attaquant choisir le calendrier. Les deux options sont médiocres, mais une seule est évitable.

Exemple reproductible : limiter un jeton Git aux fichiers nécessaires

Section intitulée « Exemple reproductible : limiter un jeton Git aux fichiers nécessaires »

Git peut stocker des identifiants via un gestionnaire natif, mais la configuration locale ne doit jamais contenir un jeton en clair. L’exemple suivant utilise un jeton injecté temporairement dans la commande, puis vérifie qu’aucune adresse distante n’embarque un secret.

Fenêtre de terminal
# Désactiver le stockage persistant d'identifiants Git dans ce dépôt.
git config --local --unset-all credential.helper 2>/dev/null || true
# Utiliser un jeton court fourni par un gestionnaire de secrets ou une fédération.
# La variable TOKEN ne doit pas être exportée dans un profil shell permanent.
git -c http.extraHeader="Authorization: Bearer ${TOKEN}" \
ls-remote https://git.example.internal/equipe/projet.git HEAD
# Vérifier que la configuration distante ne contient aucun identifiant.
git remote -v
# Effacer la variable dès la fin de l'opération dans le shell courant.
unset TOKEN

Cette commande ne rend pas le jeton invulnérable. Un processus local exécuté avec les droits de la session peut encore lire certains environnements ou intercepter une commande selon le système. Son intérêt est de réduire la persistance et d’empêcher la fuite banale dans .git/config, les captures de support ou les sauvegardes. Pour les opérations fréquentes, préférer un gestionnaire d’identifiants intégré au système et administré par la politique de poste.

Supervision, sauvegarde et réponse à la compromission

Section intitulée « Supervision, sauvegarde et réponse à la compromission »

Superviser un poste de développement signifie collecter ce qui permet de décider vite : connexions aux dépôts, élévations de privilèges, installation d’extensions, modification des règles de sécurité, création de clés SSH, accès aux registres et échecs d’authentification. Les journaux locaux seuls ne suffisent pas : un attaquant ayant des privilèges élevés peut les supprimer ou les altérer.

Les alertes doivent viser des signaux concrets : nouveau jeton créé puis utilisé depuis une localisation inhabituelle, clé SSH ajoutée hors processus, exfiltration massive depuis un dépôt, extension installée hors catalogue, désactivation d’agent de sécurité, ou commande de build lançant un processus réseau inattendu. Alerter sur chaque commande git pull produit seulement un cimetière de notifications.

La sauvegarde du poste doit exclure les secrets exportables lorsque leur restauration n’est pas nécessaire. Sauvegarder une clé privée sans contrôle d’accès transforme la sauvegarde en second poste compromis, souvent avec une conservation plus longue. Les dépôts de code se restaurent depuis leur plateforme centrale ; les environnements locaux se reconstruisent depuis des définitions versionnées ; les secrets se réémettent depuis leur autorité. Cette distinction conditionne une reprise propre.

En cas de compromission suspectée, considérer tous les secrets accessibles depuis le poste comme exposés. Révoquer les sessions, les jetons, les clés SSH et les certificats concernés, puis reconstruire le poste depuis une image connue. Nettoyer manuellement une machine compromise n’apporte aucune preuve suffisante d’absence de persistance. Un poste est remplaçable, une confiance fantasmée l’est beaucoup moins.

Sans ce durcissement, la porte reste ouverte : faute d’inventaire des extensions, des jetons et des clés présents sur les postes, le périmètre d’une compromission ne peut plus être délimité, et la révocation devient un pari plutôt qu’une opération. La traçabilité disparaît en premier : une action de build ou une signature ne se rattache plus à une personne, seulement à une machine dont l’état exact est inconnu. En aval, les artefacts produits continuent d’être consommés comme légitimes par les environnements qui leur font confiance, bien après l’intrusion. La reprise coûte alors une rotation totale des secrets, sans cartographie des dépendances, avec interruption des chaînes de publication. Le délai de détection s’allonge d’autant que les journaux restent locaux, donc modifiables par celui qui a obtenu les privilèges.

Un ordinateur de développement contient souvent le code des applications et les moyens d’accéder aux services qui fabriquent, testent ou publient ce code. Il peut aussi contenir des mots de passe temporaires, des clés privées et des sessions déjà ouvertes dans un navigateur. Si un programme malveillant prend le contrôle de cet ordinateur, il peut lire ces éléments, modifier du code ou utiliser les accès de la personne connectée.

La protection commence par séparer les usages. Un ordinateur utilisé pour la messagerie et la navigation courante ne devrait pas aussi permettre de modifier les systèmes sensibles. Le système doit recevoir ses mises à jour, chiffrer son disque, bloquer les connexions non demandées et limiter les droits d’administration. Les logiciels ajoutés à l’éditeur de code et les bibliothèques téléchargées doivent être contrôlés, car ils peuvent exécuter du code sur la machine.

Les accès doivent être courts et limités à une tâche précise. Lorsqu’un accès est volé, il doit expirer vite ou pouvoir être annulé. Les clés utilisées pour prouver l’origine d’un logiciel doivent être protégées séparément. Enfin, les événements sont envoyés vers un système central pour détecter une installation inhabituelle, une nouvelle clé ou un téléchargement massif. Si la machine semble compromise, il faut annuler ses accès et la reconstruire plutôt que tenter de lui faire confiance après un nettoyage.

À lire aussi

Pages voisines