Aller au contenu
English
CI/CD & Automatisation medium

Runner groups : cloisonner ce qu'une exécution peut atteindre

Read this page in English

25 min de lecture

La question habituelle sur un runner auto-hébergé est « peut-il être compromis ? ». La bonne question est « que peut atteindre un runner compromis ? ». Les runner groups répondent à la première moitié, en décidant quels dépôts utilisent quelles machines. La frontière réseau répond à la seconde, et c'est elle qui détermine l'ampleur d'un incident.

  • Comprendre ce qu'un runner group contrôle, et ce qu'il ne contrôle pas
  • Connaître la disponibilité réelle selon votre plan GitHub
  • Cloisonner par environnement plutôt que par commodité
  • Raisonner en frontière réseau, au-delà du durcissement de la machine

Un runner group rassemble des runners auto-hébergés et porte une politique d'accès : quels dépôts de l'organisation ont le droit d'y envoyer des jobs. Sans groupes, tous les runners de l'organisation sont accessibles à tous les dépôts qui en dépendent, ce qui revient à traiter un dépôt de prototypage comme un dépôt de production.

Deux points de disponibilité déterminent ce que vous pouvez en faire :

  • toute organisation dispose d'un groupe par défaut, qui existe sans configuration ;
  • créer des groupes additionnels au niveau de l'organisation demande au minimum le plan GitHub Team.

Un troisième point est plus important que les deux précédents : par défaut, seuls les dépôts privés accèdent aux runners d'un groupe. Ce défaut est prudent, et il est possible de le surcharger. La documentation GitHub est explicite sur le risque associé, et vaut d'être citée telle quelle :

Nous recommandons de n'utiliser des runners auto-hébergés qu'avec des dépôts privés. En effet, les forks de votre dépôt public peuvent potentiellement exécuter du code dangereux sur votre machine runner, en créant une pull request qui exécute ce code dans un workflow.

Le découpage spontané suit l'organisation des équipes. Le découpage utile suit le niveau de confiance et les accès réseau.

GroupeDépôts autorisésCe que la machine atteint
runners-devDépôts de développementRien de sensible, sortie internet filtrée
runners-buildDépôts applicatifsRegistre interne en écriture, pas de production
runners-prodLe seul dépôt de déploiementProduction, secrets de déploiement

La propriété recherchée est simple à formuler : un job de dépôt de développement ne doit jamais s'exécuter sur une machine qui atteint la production. Sans cloisonnement, une dépendance compromise dans un projet secondaire donne un point d'appui sur le réseau de production, alors que le dépôt de production lui-même est irréprochable.

Le ciblage se fait par les labels du runner, côté workflow :

jobs:
deploy:
runs-on: [self-hosted, linux, x64, prod]

Ce ciblage exprime une intention, il n'applique aucune politique. C'est le runner group, côté organisation, qui refuse le job si le dépôt n'a pas accès. Un label mal orthographié laisse le job en attente indéfiniment plutôt que de le router vers un groupe voisin, ce qui est le comportement souhaitable.

La frontière réseau, ce que le cloisonnement ne couvre pas

Section intitulée « La frontière réseau, ce que le cloisonnement ne couvre pas »

Un runner group décide qui exécute où. Il ne dit rien de ce que la machine peut joindre une fois le job lancé. C'est pourtant cette seconde dimension qui fixe le coût d'un incident.

Posez-vous la question dans l'ordre d'une attaque réelle :

Qui peut déclencher le workflow ?
|
v
Quel code s'exécute, et d'où vient-il ?
|
v
Sur quelle machine, dans quel segment réseau ?
|
v
Que cette machine peut-elle joindre, en sortie comme en interne ?
|
v
Quels secrets sont présents dans l'environnement ?
|
v
Quel artefact est produit, et qui le consomme ensuite ?

Un runner auto-hébergé est presque toujours placé sur le réseau interne, c'est d'ailleurs sa raison d'être. Il hérite donc d'un accès que les runners hébergés n'ont pas : bases de données, registres internes, API d'administration, hyperviseurs. Trois mesures bornent cet héritage :

  • Segmenter. Le runner vit dans un réseau dédié, avec des règles de filtrage explicites vers les seules destinations nécessaires. Un runner qui peut joindre tout le réseau interne annule le bénéfice du cloisonnement par groupes.
  • Rendre éphémère. Une machine détruite après chaque job ne transmet rien au job suivant. C'est la seule mesure qui neutralise la persistance, le risque propre aux runners auto-hébergés.
  • Filtrer le trafic sortant. Un job compromis a besoin d'un canal pour exfiltrer. Restreindre les destinations autorisées transforme une fuite en échec de workflow, donc en signal visible.

Le contrôle le plus révélateur ne demande aucun outil. Sur chaque groupe de runners, listez ce que la machine atteint réellement, puis comparez à ce dont les jobs ont besoin.

DestinationNécessaire aux jobsAccessible depuis le runner
Registre de conteneurs interneOui, en écritureOui
Dépôt de paquets interneOui, en lectureOui
Base de données de productionNonOui
API d'administration de l'hyperviseurNonOui

Les deux dernières lignes sont le résultat habituel du premier passage. Elles ne traduisent pas une négligence, mais la façon dont les runners sont provisionnés : sur le réseau d'administration, parce que c'est là qu'était la place disponible. Chaque ligne en gras est une capacité offerte gratuitement à un attaquant qui prendrait pied sur la machine.

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • Un runner group décide quels dépôts accèdent à quels runners ; sans groupes, tous les dépôts partagent le même parc.
  • Toute organisation a un groupe par défaut ; créer des groupes additionnels demande au minimum GitHub Team.
  • Par défaut, seuls les dépôts privés accèdent aux runners d'un groupe, et surcharger ce défaut retire le garde-fou posé par GitHub.
  • Dépôt public et runner auto-hébergé ne vont pas ensemble : n'importe quelle pull request devient une exécution de code arbitraire sur votre réseau.
  • Cloisonnez par niveau de confiance et accès réseau, pas par équipe : un job de développement ne doit pas tourner là où la production est joignable.
  • Les labels expriment une intention côté workflow ; c'est la politique du groupe qui applique le refus.
  • La question qui fixe le coût d'un incident n'est pas « le runner peut-il être compromis » mais « que peut-il atteindre » : segmenter, rendre éphémère, filtrer la sortie.
  • ACT : Rejouer un workflow en local, ce qui évite d'exposer un runner auto-hébergé pour de simples essais.
  • ActionLint : Le linter qui signale un label de runner inconnu, cause classique d'un job qui attend indéfiniment.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn