infra : le socket Docker ne fuit plus dans les conteneurs de tâche (#103) #189
Labels
No labels
Compat/Breaking
EC01
EC02
EC03
EC04
EC05
EC06
Kind/BDD
Kind/Back
Kind/Bug
Kind/CICD
Kind/Cloud
Kind/Contenu
Kind/Data
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Front
Kind/IA
Kind/Infra
Kind/Monitoring
Kind/Security
Kind/Testing
Portée/Post-jury
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
ops/alerte
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
g2/enervision!189
Loading…
Reference in a new issue
No description provided.
Delete branch "gabriel/103-retirer-socket-taches"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ferme #103.
container.docker_hostportait le chemin explicite du socket Docker de l'hôte. Avec forgejo-runner, cette forme partage ce même socket avec chaque conteneur de tâche, sans qu'aucun workflow ne l'ait déclaré ni qu'unvalid_volumesvide ne s'y oppose — n'importe quelle poussée disposait donc d'un accès root sur le serveur.infra/compose/forge/runner-config.yml:docker_host: "-". Le runner garde son propre accès (nécessaire pour créer ses conteneurs de tâche) mais ne le repartage plus.infra/ansible/roles/ci_runner/tasks/main.yml: garde-fou ajouté à l'assertion de conformité pour empêcher toute régression silencieuse sur ce champ.docs/FORGE.md§5 : corrige la portée du risque, qui concernait les tâches et pas seulement l'exécuteur, et référence désormais ce fichier plutôt quedocs/SECURITE-forge.md(inexistant, deux mentions mortes corrigées au passage dansdocker-compose.yml)..forgejo/workflows/verif-socket-docker.yml: sonde manuelle (workflow_dispatch), qui installe le client Docker et attend quedocker versionéchoue dans la tâche. Un échec de cette étape est le résultat attendu.Vérifié en local : bancs
test-runner-reproductible.sh,test-hygiene-workflows.sh,test-liens-markdown.shettest-verifier-images.sh, tous verts ;test-role-app.ymlrejoué sans régression.Reste à faire, hors dépôt : appliquer sur le serveur (
ansible-playbook site.yml --tags ci, hors chaîne en cours), puis déclencher le workflow d'essai et une exécution normale de la chaîne pour les deux journaux de preuve demandés par le ticket.🤖 Generated with Claude Code
https://claude.ai/code/session_01NECwhiHyPhse3ZiCeYnr53
Approuvée. Le changement est juste et la faille est réelle : le serveur tourne encore avec la valeur vulnérable, vérifié à l'instant.
Ce que j'ai vérifié plutôt que déduit
Aucun job n'a besoin du socket dans son conteneur. C'était le seul risque de régression, et je m'attendais à en trouver un. Le seul
docker composedes workflows est dansdeploy.yml:Il passe par Ansible sur la cible, en SSH, donc hors du conteneur de tâche. Le reste de
ci.ymlne fait que du git, du node et du sh. Rien ne casse.Le garde-fou dans l'assertion du rôle
ci_runnerest au bon endroit, et sonfail_msgdit la conséquence et pas seulement la règle. Le workflow de sonde enworkflow_dispatchest une bonne idée : un contrôle dont le succès est l'échec dedocker versionse lit sans commentaire.Une chose à ne pas oublier au moment d'appliquer
--tags cin'est jamais joué par le déploiement continu, etsite.ymlexplique pourquoi en capitales : la chaîne tourne sur cet exécuteur, elle ne doit pas pouvoir le redémarrer au milieu de son propre job. C'est donc un geste manuel, hors chaîne en cours, comme tu l'écris. Je le mentionne parce que c'est exactement le genre de détail qui fait qu'une correction de sécurité reste six jours dansdevelopsans être en service.Je n'ai pas pu éprouver l'effet sur une tâche vivante, il n'y en avait aucune en cours au moment où j'ai regardé. Ta sonde le fera mieux que moi.
Un point qui n'est pas technique
Le corps de cette demande se termine par « Generated with Claude Code » et un lien de session. C'est la seule des cinquante dernières demandes du dépôt dans ce cas.
Sur une demande de sécurité, dans un dépôt qu'un jury va lire, ça se retire. Je ne le fais pas à ta place, c'est ton texte.
Relu, et le fond est juste — approuvé
Ce que j'ai vérifié moi-même, pas seulement relu
La sémantique de
docker_hostest la bonne, et c'est celle d'amont. Vérifié sur l'image effectivement déployée,forgejo-runner v6.4.0, en lui faisant cracher son propregenerate-config:"-"est littéralement la valeur par défaut d'amont : le runner trouve son démon, les conteneurs de tâche n'ont rien. La correction va dans le bon sens et ne prive pas l'exécuteur de ce dont il a besoin.Aucune tâche de la chaîne ne dépend du socket. Les quatre jobs (
python,dashboard,repo,meta) n'appellent jamais le client Docker, et ledocker compose psdedeploy.ymls'exécute sur la cible à travers Ansible en SSH, pas dans le conteneur de tâche. Le risque nommé au ticket (« une tâche qui en dépendrait sans qu'on le sache ») est bien nul.Le label
ubuntu-24.04de la sonde est réellement enregistré. Il ne vit pas dans le fichier versionné mais dans.runnersur le serveur, et aucun workflow existant ne s'en servait — donc ça méritait d'être constaté plutôt que supposé. Le.runnerdéployé porte bienubuntu-24.04:docker://ubuntu:24.04. La sonde sera prise, elle ne restera pas en attente.Fusionner ne change rien en production, et le retour arrière tient bien en une ligne. La configuration en service porte encore
unix:///var/run/docker.sock, etdeploy.ymlne joue pas l'étiquetteci— le banctest-runner-reproductible.shle surveille même explicitement. Comparé le fichier en service au fichier de référence du clone : le seul écart fonctionnel est cette ligne, tout le reste n'est que commentaire. Le--tags cirestant à jouer n'emporte donc pas d'effet de bord caché.Bancs et chaîne. Les quatre bancs rejoués en local sur la branche, verts (
test-hygiene-workflows.shprend d'ailleurs déjà le nouveau workflow en charge tout seul). Les 5 jobs de la chaîne verts sur3bde1cd. Plus aucune référence àdocs/SECURITE-forge.mdnulle part. La huitième condition du rôle porte bien sonis defined, donc le contrôle « les conditions tolèrent une clé absente » continue de passer sans qu'il ait fallu y toucher.Deux remarques, aucune bloquante
1. Le commentaire d'en-tête de la sonde dit l'inverse du script.
. forgejo/workflows/verif-socket-docker.yml, lignes 8-9 :Or le script fait le contraire, et il fait bien : le job réussit quand
docker versionéchoue, et échoue (exit 1) quand Docker répond. C'est la bonne convention — mais le commentaire, lui, invite à lire un rouge comme une preuve de succès. Ça compte parce que le livrable du ticket est précisément les deux journaux de preuve : en relisant cet en-tête au moment de commenter le run, on risque d'étiqueter le résultat à l'envers. La description de la demande porte la même ambiguïté (« Un échec de cette étape est le résultat attendu »). Deux lignes de commentaire à retourner.2. Rien dans la chaîne ne rattrape une régression de
docker_host. L'assertion ajoutée au rôle est la bonne idée, mais elle lit la configuration depuis le clone sur la cible (slurpdeci_runner_config_src) : elle ne se déclenche donc qu'au moment d'un--tags ci. Etinfra-ansible.ymlne joue que yamllint,--syntax-check,ansible-lintettest-role-app.yml— qui couvre le rôleapp, pasci_runner. Conséquence : un retour àunix:///var/run/docker.sockdansrunner-config.ymlpasse la chaîne au vert, et ne se voit qu'au prochain déploiement de l'étiquetteci.Or
tests/ci/test-runner-reproductible.shinterroge déjà ce même fichier pournetwork,force_pull,cache.enabledetcapacity. Un cas de plus au même endroit ferme la boucle en quatre lignes, et le banc est déjà joué parci.yml— sur une propriété de sécurité qui vaut root sur la machine, ça me paraît le bon endroit pour l'attraper.Je fusionne : rien de tout ça ne justifie de retenir la correction, qui referme un accès root sur simple poussée. Les deux points ci-dessus se traitent en un commit de suite, à faire pendant que tu joues
--tags ciet les deux runs de preuve.