{"id":504,"date":"2026-03-01T20:21:31","date_gmt":"2026-03-01T19:21:31","guid":{"rendered":"https:\/\/secure-pipelines.com\/?p=504"},"modified":"2026-07-06T20:32:33","modified_gmt":"2026-07-06T19:32:33","slug":"network-filesystem-restrictions-ci-cd-build-environments","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/network-filesystem-restrictions-ci-cd-build-environments\/","title":{"rendered":"Restrictions R\u00e9seau et Syst\u00e8me de Fichiers pour les Environnements de Build CI\/CD"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Les pipelines CI\/CD comptent parmi les charges de travail les plus privil\u00e9gi\u00e9es d\u2019une organisation. Ils r\u00e9cup\u00e8rent le code source, t\u00e9l\u00e9chargent les d\u00e9pendances, acc\u00e8dent aux secrets et poussent des artefacts vers les registres de production. Pourtant, dans de nombreux environnements, les processus de build derri\u00e8re ces pipelines s\u2019ex\u00e9cutent avec un acc\u00e8s r\u00e9seau illimit\u00e9 et des permissions compl\u00e8tes sur le syst\u00e8me de fichiers \u2014 une combinaison qui repr\u00e9sente l\u2019une des failles les plus exploitables de la livraison logicielle moderne.<\/p>\n\n<p class=\"wp-block-paragraph\">Lorsqu\u2019un environnement de build peut joindre n\u2019importe quelle adresse IP et \u00e9crire sur n\u2019importe quel chemin du disque, une seule d\u00e9pendance compromise ou une pull request malveillante peut exfiltrer des secrets, alt\u00e9rer des artefacts ou installer des portes d\u00e9rob\u00e9es persistantes. Ce guide pr\u00e9sente des techniques concr\u00e8tes pour verrouiller l\u2019acc\u00e8s r\u00e9seau et l\u2019acc\u00e8s au syst\u00e8me de fichiers dans les environnements de build CI\/CD, des NetworkPolicies Kubernetes aux syst\u00e8mes de build herm\u00e9tiques.<\/p>\n\n<h2 class=\"wp-block-heading\">Pourquoi les environnements de build non restreints sont dangereux<\/h2>\n\n<p class=\"wp-block-paragraph\">Avant de plonger dans les solutions, il convient de comprendre les menaces sp\u00e9cifiques que cr\u00e9ent les environnements de build non restreints. Ces risques ne sont pas th\u00e9oriques \u2014 ils ont \u00e9t\u00e9 exploit\u00e9s dans de v\u00e9ritables attaques de la cha\u00eene d\u2019approvisionnement logicielle.<\/p>\n\n<h3 class=\"wp-block-heading\">Exfiltration de donn\u00e9es<\/h3>\n\n<p class=\"wp-block-paragraph\">Les environnements de build ont fr\u00e9quemment acc\u00e8s \u00e0 des secrets : cl\u00e9s API, identifiants de registre, cl\u00e9s de signature et tokens de d\u00e9ploiement. Si un processus de build dispose d\u2019un acc\u00e8s r\u00e9seau sortant illimit\u00e9, une d\u00e9pendance compromise peut envoyer ces secrets vers un serveur contr\u00f4l\u00e9 par un attaquant. Cela peut se produire via un script <code>postinstall<\/code> malveillant dans un paquet npm, une d\u00e9pendance PyPI compromise ou m\u00eame une cible Makefile sp\u00e9cialement con\u00e7ue. Sans restrictions r\u00e9seau, il n\u2019existe aucune barri\u00e8re entre le secret et le point de terminaison de l\u2019attaquant.<\/p>\n\n<h3 class=\"wp-block-heading\">Attaques de la cha\u00eene d\u2019approvisionnement<\/h3>\n\n<p class=\"wp-block-paragraph\">Un attaquant capable d\u2019ex\u00e9cuter du code arbitraire pendant un build peut modifier les artefacts produits. Si le syst\u00e8me de fichiers est accessible en \u00e9criture sans restriction, les binaires compil\u00e9s, les images de conteneurs ou les manifestes de d\u00e9ploiement peuvent \u00eatre alt\u00e9r\u00e9s apr\u00e8s l\u2019\u00e9tape de build l\u00e9gitime mais avant que l\u2019artefact ne soit pouss\u00e9. C\u2019est l\u2019essence de nombreuses attaques de la cha\u00eene d\u2019approvisionnement \u2014 le code source para\u00eet sain, mais l\u2019artefact livr\u00e9 est empoisonn\u00e9.<\/p>\n\n<h3 class=\"wp-block-heading\">Mouvement lat\u00e9ral<\/h3>\n\n<p class=\"wp-block-paragraph\">Les environnements de build qui partagent un r\u00e9seau avec d\u2019autres infrastructures (bases de donn\u00e9es, API internes, services de m\u00e9tadonn\u00e9es cloud) offrent \u00e0 un attaquant un point de pivot. Un job de build compromis peut scanner les r\u00e9seaux internes, acc\u00e9der aux points de terminaison de m\u00e9tadonn\u00e9es d\u2019instance cloud (comme <code>169.254.169.254<\/code>) et passer d\u2019un contexte CI\/CD \u00e0 un acc\u00e8s plus large \u00e0 l\u2019infrastructure.<\/p>\n\n<h2 class=\"wp-block-heading\">Restrictions r\u00e9seau<\/h2>\n\n<p class=\"wp-block-paragraph\">Le contr\u00f4le le plus efficace que vous puissiez mettre en place est de restreindre l\u2019acc\u00e8s r\u00e9seau sortant des environnements de build. Les builds doivent r\u00e9cup\u00e9rer des d\u00e9pendances et pousser des artefacts \u2014 mais ils ont rarement besoin d\u2019un acc\u00e8s Internet illimit\u00e9.<\/p>\n\n<h3 class=\"wp-block-heading\">NetworkPolicy Kubernetes pour les pods runner<\/h3>\n\n<p class=\"wp-block-paragraph\">Si vous ex\u00e9cutez vos runners CI\/CD sur Kubernetes (par exemple avec Actions Runner Controller ou l\u2019ex\u00e9cuteur Kubernetes de GitLab), les ressources NetworkPolicy vous offrent un contr\u00f4le fin de l\u2019acc\u00e8s r\u00e9seau au niveau du pod. Une politique bien con\u00e7ue refuse tout le trafic sortant par d\u00e9faut, puis n\u2019autorise que les points de terminaison sp\u00e9cifiques dont le build a besoin.<\/p>\n\n<pre><code>apiVersion: networking.k8s.io\/v1\nkind: NetworkPolicy\nmetadata:\n  name: ci-runner-netpol\n  namespace: ci-runners\nspec:\n  podSelector:\n    matchLabels:\n      app: ci-runner\n  policyTypes:\n    - Egress\n  egress:\n    # Allow DNS resolution\n    - to:\n        - namespaceSelector: {}\n      ports:\n        - protocol: UDP\n          port: 53\n        - protocol: TCP\n          port: 53\n    # Allow access to container registry\n    - to:\n        - ipBlock:\n            cidr: 10.0.50.0\/24\n      ports:\n        - protocol: TCP\n          port: 443\n    # Allow access to artifact storage\n    - to:\n        - ipBlock:\n            cidr: 10.0.60.0\/24\n      ports:\n        - protocol: TCP\n          port: 443\n    # Deny everything else by omission<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Cette politique autorise les pods runner \u00e0 r\u00e9soudre le DNS, \u00e0 joindre le registre de conteneurs et \u00e0 acc\u00e9der au stockage d\u2019artefacts \u2014 rien d\u2019autre. Toute autre connexion sortante est rejet\u00e9e. Si vous utilisez un plugin CNI qui prend en charge NetworkPolicy (Calico, Cilium ou Weave Net), elle prend effet imm\u00e9diatement d\u00e8s son application.<\/p>\n\n<p class=\"wp-block-paragraph\">Pour un contr\u00f4le plus granulaire, la ressource <code>CiliumNetworkPolicy<\/code> de Cilium prend en charge des r\u00e8gles bas\u00e9es sur le DNS, vous permettant de sp\u00e9cifier des noms de domaine plut\u00f4t que des blocs d\u2019adresses IP :<\/p>\n\n<pre><code>apiVersion: cilium.io\/v2\nkind: CiliumNetworkPolicy\nmetadata:\n  name: ci-runner-cilium-policy\n  namespace: ci-runners\nspec:\n  endpointSelector:\n    matchLabels:\n      app: ci-runner\n  egress:\n    - toEndpoints:\n        - matchLabels:\n            io.kubernetes.pod.namespace: kube-system\n            k8s-app: kube-dns\n      toPorts:\n        - ports:\n            - port: \"53\"\n              protocol: ANY\n    - toFQDNs:\n        - matchName: \"ghcr.io\"\n        - matchName: \"registry.npmjs.org\"\n        - matchName: \"pypi.org\"\n      toPorts:\n        - ports:\n            - port: \"443\"\n              protocol: TCP<\/code><\/pre>\n\n<h3 class=\"wp-block-heading\">Docker &#8211;network=none<\/h3>\n\n<p class=\"wp-block-paragraph\">Pour les \u00e9tapes de build bas\u00e9es sur Docker qui ne devraient n\u00e9cessiter aucun acc\u00e8s r\u00e9seau (compilation, analyse statique, tests unitaires), vous pouvez supprimer enti\u00e8rement l\u2019acc\u00e8s r\u00e9seau en ex\u00e9cutant le conteneur avec <code>--network=none<\/code> :<\/p>\n\n<pre><code>docker run --network=none \\\n  --rm \\\n  -v \"$(pwd)\/src:\/workspace:ro\" \\\n  -v \"$(pwd)\/output:\/output\" \\\n  my-build-image:latest \\\n  make build<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Avec <code>--network=none<\/code>, le conteneur ne dispose d\u2019aucune interface r\u00e9seau \u2014 pas m\u00eame la boucle locale dans certaines configurations. C\u2019est l\u2019isolation r\u00e9seau la plus forte que vous puissiez obtenir pour une \u00e9tape de build. L\u2019essentiel est de structurer votre pipeline de sorte que la r\u00e9cup\u00e9ration des d\u00e9pendances se fasse dans une \u00e9tape (avec un acc\u00e8s r\u00e9seau limit\u00e9) et que le build proprement dit se d\u00e9roule dans une \u00e9tape distincte, sans r\u00e9seau.<\/p>\n\n<h3 class=\"wp-block-heading\">R\u00e8gles de pare-feu pour les runners auto-h\u00e9berg\u00e9s<\/h3>\n\n<p class=\"wp-block-paragraph\">Si vous utilisez des runners auto-h\u00e9berg\u00e9s sur des VM plut\u00f4t que dans des conteneurs, des r\u00e8gles de pare-feu au niveau de l\u2019h\u00f4te offrent une protection \u00e9quivalente. Sous Linux, des r\u00e8gles <code>iptables<\/code> ou <code>nftables<\/code> peuvent restreindre le trafic sortant du compte utilisateur qui ex\u00e9cute les jobs CI :<\/p>\n\n<pre><code># Allow DNS\niptables -A OUTPUT -m owner --uid-owner ci-runner -p udp --dport 53 -j ACCEPT\niptables -A OUTPUT -m owner --uid-owner ci-runner -p tcp --dport 53 -j ACCEPT\n\n# Allow HTTPS to specific registries\niptables -A OUTPUT -m owner --uid-owner ci-runner -p tcp --dport 443 \\\n  -d registry.example.com -j ACCEPT\niptables -A OUTPUT -m owner --uid-owner ci-runner -p tcp --dport 443 \\\n  -d ghcr.io -j ACCEPT\n\n# Deny all other outbound traffic from the CI runner\niptables -A OUTPUT -m owner --uid-owner ci-runner -j DROP<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Cette approche fonctionne bien lorsque vous ex\u00e9cutez l\u2019agent CI sous un compte utilisateur d\u00e9di\u00e9 et que vous devez laisser le syst\u00e8me h\u00f4te lui-m\u00eame conserver une connectivit\u00e9 plus large pour l\u2019administration et les mises \u00e0 jour.<\/p>\n\n<h3 class=\"wp-block-heading\">Mise en liste d\u2019autorisation des registres et des API<\/h3>\n\n<p class=\"wp-block-paragraph\">Quel que soit le m\u00e9canisme d\u2019application, le principe est le m\u00eame : tout refuser en sortie par d\u00e9faut, puis n\u2019autoriser que ce dont le build a r\u00e9ellement besoin. Une liste d\u2019autorisation typique inclut le registre de paquets (npm, PyPI, Maven Central), le registre de conteneurs (Docker Hub, GHCR, ECR), l\u2019API de la plateforme CI\/CD (pour les mises \u00e0 jour de statut et les t\u00e9l\u00e9versements d\u2019artefacts) et \u00e9ventuellement un proxy ou un miroir que vous contr\u00f4lez. Tout le reste devrait \u00eatre bloqu\u00e9. Utilisez autant que possible un proxy ou un miroir interne pour les d\u00e9pendances \u2014 cela r\u00e9duit la liste d\u2019autorisation \u00e0 un seul point de terminaison et vous offre gratuitement la mise en cache et la journalisation d\u2019audit.<\/p>\n\n<h2 class=\"wp-block-heading\">Restrictions du syst\u00e8me de fichiers<\/h2>\n\n<p class=\"wp-block-paragraph\">Les restrictions r\u00e9seau emp\u00eachent les donn\u00e9es de quitter l\u2019environnement de build. Les restrictions du syst\u00e8me de fichiers emp\u00eachent les modifications non autoris\u00e9es en son sein. Ensemble, elles constituent une solide posture de d\u00e9fense en profondeur.<\/p>\n\n<h3 class=\"wp-block-heading\">Syst\u00e8me de fichiers racine en lecture seule<\/h3>\n\n<p class=\"wp-block-paragraph\">Ex\u00e9cuter les conteneurs de build avec un syst\u00e8me de fichiers racine en lecture seule emp\u00eache tout processus de modifier l\u2019image de base. Cela bloque une cat\u00e9gorie d\u2019attaques o\u00f9 du code malveillant modifie les binaires syst\u00e8me, installe des portes d\u00e9rob\u00e9es ou alt\u00e8re la configuration des outils de build au niveau du syst\u00e8me.<\/p>\n\n<p class=\"wp-block-paragraph\">Dans Docker, utilisez l\u2019option <code>--read-only<\/code> :<\/p>\n\n<pre><code>docker run --read-only \\\n  --tmpfs \/tmp:rw,noexec,nosuid,size=512m \\\n  --tmpfs \/workspace\/build:rw,size=2g \\\n  -v \"$(pwd)\/src:\/workspace\/src:ro\" \\\n  my-build-image:latest \\\n  make build<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Dans Kubernetes, d\u00e9finissez le security context dans la sp\u00e9cification du pod :<\/p>\n\n<pre><code>apiVersion: v1\nkind: Pod\nmetadata:\n  name: ci-build-pod\nspec:\n  containers:\n    - name: build\n      image: my-build-image:latest\n      securityContext:\n        readOnlyRootFilesystem: true\n        runAsNonRoot: true\n        allowPrivilegeEscalation: false\n      volumeMounts:\n        - name: build-tmp\n          mountPath: \/tmp\n        - name: build-output\n          mountPath: \/workspace\/build\n        - name: source\n          mountPath: \/workspace\/src\n          readOnly: true\n  volumes:\n    - name: build-tmp\n      emptyDir:\n        medium: Memory\n        sizeLimit: 512Mi\n    - name: build-output\n      emptyDir:\n        sizeLimit: 2Gi\n    - name: source\n      configMap:\n        name: source-code<\/code><\/pre>\n\n<h3 class=\"wp-block-heading\">tmpfs pour les artefacts de build<\/h3>\n\n<p class=\"wp-block-paragraph\">Lorsque le syst\u00e8me de fichiers racine est en lecture seule, les builds ont besoin d\u2019un espace inscriptible pour les fichiers temporaires, les caches et les artefacts produits. Utilisez des montages <code>tmpfs<\/code> (adoss\u00e9s \u00e0 la RAM) ou des volumes <code>emptyDir<\/code> (dans Kubernetes) pour ces chemins. Cela pr\u00e9sente l\u2019avantage suppl\u00e9mentaire que tous les artefacts de build sont automatiquement nettoy\u00e9s \u00e0 la sortie du conteneur \u2014 aucune donn\u00e9e obsol\u00e8te ne persiste d\u2019un build \u00e0 l\u2019autre.<\/p>\n\n<p class=\"wp-block-paragraph\">Montez <code>tmpfs<\/code> avec des options restrictives autant que possible : <code>noexec<\/code> emp\u00eache l\u2019ex\u00e9cution de binaires \u00e9crits dans les r\u00e9pertoires temporaires (ce qui bloque un vecteur d\u2019attaque courant), <code>nosuid<\/code> emp\u00eache les attaques par bit SUID, et les limites <code>size<\/code> emp\u00eachent un build incontr\u00f4l\u00e9 d\u2019\u00e9puiser la m\u00e9moire de l\u2019h\u00f4te.<\/p>\n\n<h3 class=\"wp-block-heading\">Emp\u00eacher les \u00e9critures sur les chemins sensibles<\/h3>\n\n<p class=\"wp-block-paragraph\">Au-del\u00e0 du syst\u00e8me de fichiers racine, certains chemins m\u00e9ritent une protection suppl\u00e9mentaire. Montez le code source en lecture seule pour emp\u00eacher le build de modifier ses propres entr\u00e9es. Assurez-vous que <code>\/etc<\/code>, <code>\/usr<\/code> et <code>\/var<\/code> ne sont pas inscriptibles. Si le build doit \u00e9crire dans un r\u00e9pertoire personnel (pour la configuration des outils), fournissez un montage inscriptible d\u00e9di\u00e9 plut\u00f4t que de rendre tout le r\u00e9pertoire personnel inscriptible. Bloquez l\u2019acc\u00e8s aux sockets Docker, aux tokens de compte de service Kubernetes et aux fichiers d\u2019identifiants cloud en ne les montant tout simplement pas dans les conteneurs de build.<\/p>\n\n<h2 class=\"wp-block-heading\">Builds herm\u00e9tiques<\/h2>\n\n<p class=\"wp-block-paragraph\">La r\u00e9f\u00e9rence absolue en mati\u00e8re de s\u00e9curit\u00e9 des environnements de build est le build herm\u00e9tique : un build qui n\u2019a aucun acc\u00e8s r\u00e9seau et n\u2019utilise que des entr\u00e9es explicitement d\u00e9clar\u00e9es et pr\u00e9-r\u00e9cup\u00e9r\u00e9es. Les builds herm\u00e9tiques \u00e9liminent des cat\u00e9gories enti\u00e8res d\u2019attaques de la cha\u00eene d\u2019approvisionnement, car le processus de build ne peut pas t\u00e9l\u00e9charger de code qui n\u2019a pas \u00e9t\u00e9 explicitement sp\u00e9cifi\u00e9 et v\u00e9rifi\u00e9.<\/p>\n\n<h3 class=\"wp-block-heading\">Le sch\u00e9ma du build herm\u00e9tique<\/h3>\n\n<p class=\"wp-block-paragraph\">Un pipeline de build herm\u00e9tique comporte g\u00e9n\u00e9ralement deux phases. Dans la premi\u00e8re phase (la phase de r\u00e9solution\/r\u00e9cup\u00e9ration), les d\u00e9pendances sont t\u00e9l\u00e9charg\u00e9es depuis des sources approuv\u00e9es, leurs sommes de contr\u00f4le sont v\u00e9rifi\u00e9es par rapport \u00e0 un lockfile, puis elles sont stock\u00e9es dans un cache local ou un r\u00e9pertoire vendored. Cette phase n\u00e9cessite un acc\u00e8s r\u00e9seau limit\u00e9. Dans la seconde phase (la phase de build), la compilation ou l\u2019assemblage proprement dit se d\u00e9roule sans aucun acc\u00e8s r\u00e9seau. Toutes les entr\u00e9es proviennent du syst\u00e8me de fichiers local \u2014 le code source et les d\u00e9pendances pr\u00e9-r\u00e9cup\u00e9r\u00e9es.<\/p>\n\n<pre><code># Phase 1: Fetch dependencies (limited network)\ndocker run --network=ci-restricted \\\n  -v \"$(pwd):\/workspace\" \\\n  my-build-image:latest \\\n  sh -c \"cd \/workspace && npm ci --ignore-scripts\"\n\n# Phase 2: Build (no network)\ndocker run --network=none \\\n  --read-only \\\n  --tmpfs \/tmp:rw,noexec,size=512m \\\n  -v \"$(pwd):\/workspace:ro\" \\\n  -v \"$(pwd)\/dist:\/dist\" \\\n  my-build-image:latest \\\n  sh -c \"cd \/workspace && npm run build && cp -r build\/* \/dist\/\"<\/code><\/pre>\n\n<h3 class=\"wp-block-heading\">Bazel et les builds herm\u00e9tiques<\/h3>\n\n<p class=\"wp-block-paragraph\">Bazel est con\u00e7u autour de l\u2019herm\u00e9tisme. Avec <code>--sandbox_default_allow_network=false<\/code>, Bazel bloque l\u2019acc\u00e8s r\u00e9seau pendant les actions de build par d\u00e9faut. Les d\u00e9pendances sont d\u00e9clar\u00e9es dans les fichiers <code>WORKSPACE<\/code> ou <code>MODULE.bazel<\/code> avec des hachages SHA-256 explicites, et Bazel les r\u00e9cup\u00e8re dans une phase distincte avant le d\u00e9but du build. Si une d\u00e9pendance ne correspond pas au hachage d\u00e9clar\u00e9, le build \u00e9choue.<\/p>\n\n<pre><code># In .bazelrc\nbuild --sandbox_default_allow_network=false\nbuild --incompatible_strict_action_env\nfetch --repository_cache=\/shared\/bazel-cache\/repos<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Cela rend les builds Bazel reproductibles et r\u00e9sistants aux attaques par confusion de d\u00e9pendances. Chaque entr\u00e9e est adress\u00e9e par son contenu et v\u00e9rifi\u00e9e.<\/p>\n\n<h3 class=\"wp-block-heading\">Nix et les builds reproductibles<\/h3>\n\n<p class=\"wp-block-paragraph\">Nix adopte une approche similaire. Chaque d\u00e9rivation de build sp\u00e9cifie ses entr\u00e9es par hachage de contenu, et le sandbox de build de Nix bloque l\u2019acc\u00e8s r\u00e9seau par d\u00e9faut. La commande <code>nix-build<\/code> r\u00e9cup\u00e8re toutes les sources dans le store Nix (en v\u00e9rifiant les hachages), puis ex\u00e9cute le build dans un environnement isol\u00e9 sans r\u00e9seau et avec un syst\u00e8me de fichiers minimal. Cela garantit que les builds sont reproductibles \u2014 les m\u00eames entr\u00e9es produisent toujours la m\u00eame sortie.<\/p>\n\n<h2 class=\"wp-block-heading\">Mise en \u0153uvre pratique<\/h2>\n\n<p class=\"wp-block-paragraph\">Voyons comment mettre en \u0153uvre ces restrictions dans des plateformes CI\/CD sp\u00e9cifiques.<\/p>\n\n<h3 class=\"wp-block-heading\">GitHub Actions avec Actions Runner Controller (ARC) + NetworkPolicy<\/h3>\n\n<p class=\"wp-block-paragraph\">Si vous utilisez <a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/lab-ephemeral-self-hosted-runners-actions-runner-controller\/\">Actions Runner Controller<\/a> pour ex\u00e9cuter GitHub Actions sur Kubernetes, vous pouvez appliquer des NetworkPolicies directement aux pods runner. ARC cr\u00e9e des pods avec des labels pr\u00e9visibles, ce qui les rend faciles \u00e0 cibler avec des politiques.<\/p>\n\n<pre><code>apiVersion: actions.summerwind.dev\/v1alpha1\nkind: RunnerDeployment\nmetadata:\n  name: secure-runner\n  namespace: ci-runners\nspec:\n  replicas: 3\n  template:\n    metadata:\n      labels:\n        app: ci-runner\n        security-tier: restricted\n    spec:\n      containers:\n        - name: runner\n          securityContext:\n            readOnlyRootFilesystem: true\n            runAsNonRoot: true\n            allowPrivilegeEscalation: false\n            capabilities:\n              drop:\n                - ALL\n          volumeMounts:\n            - name: work\n              mountPath: \/runner\/_work\n            - name: tmp\n              mountPath: \/tmp\n      volumes:\n        - name: work\n          emptyDir:\n            sizeLimit: 10Gi\n        - name: tmp\n          emptyDir:\n            medium: Memory\n            sizeLimit: 1Gi\n---\napiVersion: networking.k8s.io\/v1\nkind: NetworkPolicy\nmetadata:\n  name: secure-runner-netpol\n  namespace: ci-runners\nspec:\n  podSelector:\n    matchLabels:\n      app: ci-runner\n  policyTypes:\n    - Egress\n    - Ingress\n  ingress: []\n  egress:\n    - to:\n        - namespaceSelector: {}\n      ports:\n        - protocol: UDP\n          port: 53\n    - to:\n        - ipBlock:\n            cidr: 0.0.0.0\/0\n      ports:\n        - protocol: TCP\n          port: 443<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Cette configuration refuse tout le trafic entrant (les runners ne devraient pas accepter de connexions entrantes) et limite le trafic sortant au DNS et au HTTPS. En production, remplacez le CIDR <code>0.0.0.0\/0<\/code> par des plages d\u2019adresses IP sp\u00e9cifiques pour l\u2019API de GitHub, votre registre de conteneurs et votre stockage d\u2019artefacts.<\/p>\n\n<h3 class=\"wp-block-heading\">GitLab CI avec configuration du runner<\/h3>\n\n<p class=\"wp-block-paragraph\">L\u2019ex\u00e9cuteur Kubernetes de GitLab prend en charge la configuration du security context dans le fichier <code>config.toml<\/code> du runner. Vous pouvez d\u00e9finir directement le syst\u00e8me de fichiers en lecture seule et d\u2019autres restrictions :<\/p>\n\n<pre><code># config.toml for GitLab Runner (Kubernetes executor)\n[[runners]]\n  name = \"secure-k8s-runner\"\n  executor = \"kubernetes\"\n  [runners.kubernetes]\n    namespace = \"ci-runners\"\n    image = \"alpine:latest\"\n    privileged = false\n    allow_privilege_escalation = false\n    [runners.kubernetes.pod_security_context]\n      run_as_non_root = true\n      run_as_user = 1000\n    [runners.kubernetes.build_container_security_context]\n      read_only_root_filesystem = true\n      allow_privilege_escalation = false\n      [runners.kubernetes.build_container_security_context.capabilities]\n        drop = [\"ALL\"]\n    [runners.kubernetes.volumes]\n      [[runners.kubernetes.volumes.empty_dir]]\n        name = \"build-tmp\"\n        mount_path = \"\/tmp\"\n        medium = \"Memory\"\n        size_limit = \"512Mi\"\n      [[runners.kubernetes.volumes.empty_dir]]\n        name = \"build-workspace\"\n        mount_path = \"\/builds\"\n        size_limit = \"5Gi\"<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Combinez cela avec une NetworkPolicy appliqu\u00e9e au namespace <code>ci-runners<\/code> et vous disposez \u00e0 la fois de restrictions sur le syst\u00e8me de fichiers et sur le r\u00e9seau.<\/p>\n\n<h3 class=\"wp-block-heading\">Restrictions Docker-in-Docker<\/h3>\n\n<p class=\"wp-block-paragraph\">Docker-in-Docker (DinD) est couramment utilis\u00e9 pour construire des images de conteneurs en CI. C\u2019est aussi l\u2019un des sch\u00e9mas les plus risqu\u00e9s, car il n\u00e9cessite g\u00e9n\u00e9ralement le mode privil\u00e9gi\u00e9. Si vous devez utiliser DinD, appliquez ces restrictions :<\/p>\n\n<pre><code># Use rootless DinD instead of privileged mode\nservices:\n  dind:\n    image: docker:24-dind-rootless\n    environment:\n      - DOCKER_TLS_CERTDIR=\/certs\n    volumes:\n      - dind-certs:\/certs\/client\n      - dind-data:\/var\/lib\/docker\n\n# When running builds inside DinD, pass network and filesystem restrictions\ndocker --host tcp:\/\/dind:2376 --tlsverify \\\n  run --network=none --read-only \\\n  --tmpfs \/tmp:rw,noexec,size=256m \\\n  --security-opt=no-new-privileges \\\n  my-build-image:latest make build<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Mieux encore, remplacez DinD par des outils qui n\u2019ont pas du tout besoin d\u2019un d\u00e9mon Docker. <code>kaniko<\/code>, <code>buildah<\/code> et <code>ko<\/code> peuvent construire des images de conteneurs sans acc\u00e8s privil\u00e9gi\u00e9, et ils fonctionnent bien avec des syst\u00e8mes de fichiers en lecture seule et des r\u00e9seaux restreints.<\/p>\n\n<h2 class=\"wp-block-heading\">Surveillance et audit<\/h2>\n\n<p class=\"wp-block-paragraph\">Les restrictions ne sont utiles que si vous savez quand elles sont test\u00e9es ou contourn\u00e9es. La surveillance compl\u00e8te le tableau de la s\u00e9curit\u00e9.<\/p>\n\n<h3 class=\"wp-block-heading\">D\u00e9tecter les connexions r\u00e9seau inattendues<\/h3>\n\n<p class=\"wp-block-paragraph\">Utilisez Hubble de Cilium, les flow logs de Calico ou Falco pour d\u00e9tecter les connexions r\u00e9seau que votre politique aurait d\u00fb bloquer (ou les connexions vers des destinations inhabituelles sur des ports autoris\u00e9s). Configurez des alertes pour toute requ\u00eate DNS vers des domaines absents de votre liste d\u2019autorisation, les connexions sortantes vers des ports non standard, les connexions vers des plages d\u2019adresses IP connues comme malveillantes, et tout trafic sortant provenant de pods cens\u00e9s \u00eatre en <code>--network=none<\/code>.<\/p>\n\n<pre><code># Falco rule: detect unexpected outbound connections from CI runners\n- rule: CI Runner Unexpected Outbound Connection\n  desc: Detect network connections from CI runner pods to non-approved destinations\n  condition: >\n    evt.type in (connect, sendto) and\n    container and\n    k8s.ns.name = \"ci-runners\" and\n    not (fd.sip in (approved_registry_ips) or fd.sport = 53)\n  output: >\n    Unexpected outbound connection from CI runner\n    (command=%proc.cmdline connection=%fd.name container=%container.name\n    pod=%k8s.pod.name namespace=%k8s.ns.name)\n  priority: WARNING\n  tags: [network, ci-cd, supply-chain]<\/code><\/pre>\n\n<h3 class=\"wp-block-heading\">Auditer l\u2019acc\u00e8s au syst\u00e8me de fichiers<\/h3>\n\n<p class=\"wp-block-paragraph\">Surveillez les \u00e9critures sur le syst\u00e8me de fichiers dans les conteneurs de build pour d\u00e9tecter les modifications inattendues. L\u2019outil <code>auditd<\/code> de Linux peut surveiller des chemins sp\u00e9cifiques, et Falco peut d\u00e9tecter les \u00e9critures vers des emplacements sensibles. Les chemins cl\u00e9s \u00e0 surveiller incluent <code>\/etc<\/code> et <code>\/usr<\/code> (qui ne devraient jamais \u00eatre \u00e9crits pendant un build), le chemin du socket Docker, les chemins des tokens de compte de service Kubernetes, et tout chemin contenant des identifiants ou des cl\u00e9s de signature.<\/p>\n\n<p class=\"wp-block-paragraph\">Si vous utilisez des syst\u00e8mes de fichiers racine en lecture seule, toute tentative d\u2019\u00e9criture vers un chemin prot\u00e9g\u00e9 g\u00e9n\u00e8re une erreur \u2014 journalisez ces erreurs et d\u00e9clenchez des alertes dessus. Elles indiquent soit un build mal configur\u00e9, soit une attaque potentielle.<\/p>\n\n<h2 class=\"wp-block-heading\">Compromis et exp\u00e9rience d\u00e9veloppeur<\/h2>\n\n<p class=\"wp-block-paragraph\">Des restrictions r\u00e9seau et syst\u00e8me de fichiers strictes cr\u00e9ent in\u00e9vitablement des frictions. Comprendre et g\u00e9rer ces compromis est essentiel \u00e0 une adoption r\u00e9ussie.<\/p>\n\n<h3 class=\"wp-block-heading\">Vitesse de build<\/h3>\n\n<p class=\"wp-block-paragraph\">Les builds herm\u00e9tiques exigent que toutes les d\u00e9pendances soient pr\u00e9-r\u00e9cup\u00e9r\u00e9es, ce qui ajoute une \u00e9tape au pipeline. Cependant, cela signifie aussi que les d\u00e9pendances peuvent \u00eatre mises en cache de mani\u00e8re agressive. En pratique, de nombreuses \u00e9quipes constatent que les builds herm\u00e9tiques sont en r\u00e9alit\u00e9 plus rapides, car le taux de succ\u00e8s du cache est bien plus \u00e9lev\u00e9 lorsque la r\u00e9solution des d\u00e9pendances est d\u00e9terministe. Utilisez un cache partag\u00e9 (un cache distant Bazel, un cache binaire Nix ou un simple cache HTTP pour les d\u00e9pendances vendored) pour amortir le co\u00fbt sur l\u2019ensemble des builds.<\/p>\n\n<h3 class=\"wp-block-heading\">Exp\u00e9rience d\u00e9veloppeur<\/h3>\n\n<p class=\"wp-block-paragraph\">Les d\u00e9veloppeurs rencontreront des \u00e9checs lorsque les builds tenteront d\u2019acc\u00e9der \u00e0 des points de terminaison r\u00e9seau bloqu\u00e9s ou d\u2019\u00e9crire vers des chemins en lecture seule. De bons messages d\u2019erreur sont essentiels. Encapsulez vos \u00e9tapes de build dans des scripts qui interceptent les erreurs de permission et les \u00e9checs r\u00e9seau, puis affichent des messages exploitables expliquant pourquoi l\u2019acc\u00e8s a \u00e9t\u00e9 bloqu\u00e9 et comment r\u00e9soudre le probl\u00e8me (g\u00e9n\u00e9ralement en ajoutant une d\u00e9pendance au lockfile ou en changeant le chemin de sortie).<\/p>\n\n<p class=\"wp-block-paragraph\">Envisagez un d\u00e9ploiement progressif : commencez par un mode surveillance (journaliser les violations sans bloquer), puis passez \u00e0 l\u2019application effective. Cela laisse aux \u00e9quipes le temps de mettre \u00e0 jour leurs configurations de build sans casser tous les pipelines d\u2019un coup.<\/p>\n\n<h3 class=\"wp-block-heading\">D\u00e9bogage<\/h3>\n\n<p class=\"wp-block-paragraph\">D\u00e9boguer des \u00e9checs de build dans un environnement restreint est plus difficile lorsque vous ne pouvez pas installer d\u2019outils suppl\u00e9mentaires ni joindre des services externes. Proposez un \u00ab mode d\u00e9bogage \u00bb qui assouplit les restrictions pour une ex\u00e9cution de pipeline sp\u00e9cifique, d\u00e9clench\u00e9e manuellement (jamais pour les ex\u00e9cutions automatis\u00e9es sur la branche main). Journalisez le fait que le mode d\u00e9bogage a \u00e9t\u00e9 utilis\u00e9 et qui l\u2019a d\u00e9clench\u00e9. N\u2019autorisez jamais le mode d\u00e9bogage \u00e0 contourner les restrictions sur les builds d\u2019artefacts de production.<\/p>\n\n<h2 class=\"wp-block-heading\">Tout assembler<\/h2>\n\n<p class=\"wp-block-paragraph\">Voici un r\u00e9sum\u00e9 de l\u2019approche en couches pour s\u00e9curiser les environnements de build CI\/CD :<\/p>\n\n<p class=\"wp-block-paragraph\"><strong>Couche 1 \u2014 Restrictions r\u00e9seau :<\/strong> Refus par d\u00e9faut du trafic sortant avec des listes d\u2019autorisation pour les registres et les API. Utilisez NetworkPolicy Kubernetes, <code>--network=none<\/code> de Docker ou des r\u00e8gles de pare-feu au niveau de l\u2019h\u00f4te selon votre infrastructure de runners.<\/p>\n\n<p class=\"wp-block-paragraph\"><strong>Couche 2 \u2014 Restrictions du syst\u00e8me de fichiers :<\/strong> Syst\u00e8me de fichiers racine en lecture seule, tmpfs pour les chemins inscriptibles avec limites de taille et noexec, code source mont\u00e9 en lecture seule.<\/p>\n\n<p class=\"wp-block-paragraph\"><strong>Couche 3 \u2014 Builds herm\u00e9tiques :<\/strong> S\u00e9parez la r\u00e9solution des d\u00e9pendances de la construction. Ex\u00e9cutez la phase de build sans aucun acc\u00e8s r\u00e9seau et uniquement avec des entr\u00e9es pr\u00e9-r\u00e9cup\u00e9r\u00e9es et v\u00e9rifi\u00e9es par hachage.<\/p>\n\n<p class=\"wp-block-paragraph\"><strong>Couche 4 \u2014 Surveillance :<\/strong> D\u00e9tectez les violations de politique, les connexions inattendues et les tentatives de modification du syst\u00e8me de fichiers, et d\u00e9clenchez des alertes.<\/p>\n\n<p class=\"wp-block-paragraph\">Aucune couche ne suffit \u00e0 elle seule. Des restrictions r\u00e9seau sans contr\u00f4les sur le syst\u00e8me de fichiers laissent toujours possible l\u2019alt\u00e9ration des artefacts. Des restrictions du syst\u00e8me de fichiers sans contr\u00f4les r\u00e9seau laissent toujours possible l\u2019exfiltration. Des builds herm\u00e9tiques sans surveillance vous rendent aveugle aux tentatives d\u2019attaque. Les couches se renforcent mutuellement.<\/p>\n\n<h2 class=\"wp-block-heading\">Guides connexes<\/h2>\n\n<p class=\"wp-block-paragraph\">Pour approfondir la s\u00e9curisation de votre pipeline CI\/CD, consultez ces guides connexes :<\/p>\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/build-integrity-reproducible-builds-ci-cd\/\">Int\u00e9grit\u00e9 des builds et builds reproductibles en CI\/CD<\/a> \u2014 couvre la conformit\u00e9 SLSA, la v\u00e9rification des builds reproductibles et la provenance des artefacts.<\/li>\n\n\n\n<li><a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/lab-ephemeral-self-hosted-runners-actions-runner-controller\/\">Lab : Runners auto-h\u00e9berg\u00e9s \u00e9ph\u00e9m\u00e8res avec Actions Runner Controller<\/a> \u2014 guide pratique pour d\u00e9ployer ARC sur Kubernetes avec des pods runner \u00e9ph\u00e9m\u00e8res \u00e0 usage unique.<\/li>\n<\/ul>\n\n<p class=\"wp-block-paragraph\">Commencez par les restrictions r\u00e9seau \u2014 elles offrent le plus fort impact pour le moindre effort de mise en \u0153uvre. Ajoutez ensuite les restrictions du syst\u00e8me de fichiers et progressez vers des builds herm\u00e9tiques \u00e0 mesure que la maturit\u00e9 de votre pipeline augmente. Chaque couche que vous ajoutez rend les attaques de la cha\u00eene d\u2019approvisionnement nettement plus difficiles \u00e0 ex\u00e9cuter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Les pipelines CI\/CD comptent parmi les charges de travail les plus privil\u00e9gi\u00e9es d\u2019une organisation. Ils r\u00e9cup\u00e8rent le code source, t\u00e9l\u00e9chargent les d\u00e9pendances, acc\u00e8dent aux secrets et poussent des artefacts vers les registres de production. Pourtant, dans de nombreux environnements, les processus de build derri\u00e8re ces pipelines s\u2019ex\u00e9cutent avec un acc\u00e8s r\u00e9seau illimit\u00e9 et des permissions &#8230; <a title=\"Restrictions R\u00e9seau et Syst\u00e8me de Fichiers pour les Environnements de Build CI\/CD\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/network-filesystem-restrictions-ci-cd-build-environments\/\" aria-label=\"En savoir plus sur Restrictions R\u00e9seau et Syst\u00e8me de Fichiers pour les Environnements de Build CI\/CD\">Lire la suite<\/a><\/p>\n","protected":false},"author":1,"featured_media":1223,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49,51],"tags":[],"post_folder":[],"class_list":["post-504","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ci-cd-security","category-pipeline-hardening"],"_links":{"self":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/504","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/comments?post=504"}],"version-history":[{"count":4,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/504\/revisions"}],"predecessor-version":[{"id":1224,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/504\/revisions\/1224"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/media\/1223"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/media?parent=504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/categories?post=504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/tags?post=504"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/post_folder?post=504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}