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.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- 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
Ce qu'est un runner group
Section intitulée « Ce qu'est un runner group »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.
Cloisonner par environnement, pas par commodité
Section intitulée « Cloisonner par environnement, pas par commodité »Le découpage spontané suit l'organisation des équipes. Le découpage utile suit le niveau de confiance et les accès réseau.
| Groupe | Dépôts autorisés | Ce que la machine atteint |
|---|---|---|
runners-dev | Dépôts de développement | Rien de sensible, sortie internet filtrée |
runners-build | Dépôts applicatifs | Registre interne en écriture, pas de production |
runners-prod | Le seul dépôt de déploiement | Production, 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 ? | vQuel code s'exécute, et d'où vient-il ? | vSur quelle machine, dans quel segment réseau ? | vQue cette machine peut-elle joindre, en sortie comme en interne ? | vQuels secrets sont présents dans l'environnement ? | vQuel 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 compte des accès, exercice de dix minutes
Section intitulée « Le compte des accès, exercice de dix minutes »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.
| Destination | Nécessaire aux jobs | Accessible depuis le runner |
|---|---|---|
| Registre de conteneurs interne | Oui, en écriture | Oui |
| Dépôt de paquets interne | Oui, en lecture | Oui |
| Base de données de production | Non | Oui |
| API d'administration de l'hyperviseur | Non | Oui |
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.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »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
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
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- 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.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- 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.