{"id":643,"date":"2026-03-01T20:21:31","date_gmt":"2026-03-01T19:21:31","guid":{"rendered":"https:\/\/secure-pipelines.com\/?p=643"},"modified":"2026-03-24T18:08:03","modified_gmt":"2026-03-24T17:08:03","slug":"network-filesystem-restrictions-ci-cd-build-environments","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/network-filesystem-restrictions-ci-cd-build-environments\/","title":{"rendered":"Restricciones de Red y Sistema de Archivos para Entornos de Build CI\/CD"},"content":{"rendered":"<p>Los pipelines CI\/CD se encuentran entre las cargas de trabajo m\u00e1s privilegiadas de cualquier organizaci\u00f3n. Extraen c\u00f3digo fuente, descargan dependencias, acceden a secrets y env\u00edan artefactos a registries de producci\u00f3n. Sin embargo, en muchos entornos, los procesos de build detr\u00e1s de estos pipelines se ejecutan con acceso de red sin restricciones y permisos completos sobre el sistema de archivos \u2014 una combinaci\u00f3n que representa una de las brechas m\u00e1s explotables en la entrega moderna de software.<\/p>\n<p>Cuando un entorno de build puede alcanzar cualquier direcci\u00f3n IP y escribir en cualquier ruta del disco, una sola dependencia comprometida o un pull request malicioso puede exfiltrar secrets, alterar artefactos o establecer backdoors persistentes. Esta gu\u00eda cubre t\u00e9cnicas pr\u00e1cticas para restringir el acceso de red y del sistema de archivos en entornos de build CI\/CD, desde NetworkPolicies de Kubernetes hasta sistemas de build herm\u00e9ticos.<\/p>\n<h2 class=\"wp-block-heading\">Por Qu\u00e9 los Entornos de Build Sin Restricciones Son Peligrosos<\/h2>\n<p>Antes de adentrarnos en las soluciones, vale la pena comprender las amenazas espec\u00edficas que crean los entornos de build sin restricciones. Estos riesgos no son te\u00f3ricos \u2014 han sido explotados en ataques reales a la cadena de suministro.<\/p>\n<h3 class=\"wp-block-heading\">Exfiltraci\u00f3n de Datos<\/h3>\n<p>Los entornos de build frecuentemente tienen acceso a secrets: claves API, credenciales de registries, claves de firma y tokens de despliegue. Si un proceso de build tiene acceso de red saliente sin restricciones, una dependencia comprometida puede enviar esos secrets a un servidor controlado por el atacante. Esto puede ocurrir a trav\u00e9s de un script <code>postinstall<\/code> malicioso en un paquete npm, una dependencia PyPI comprometida, o incluso un target de Makefile manipulado. Sin restricciones de red, no hay barrera entre el secret y el endpoint del atacante.<\/p>\n<h3 class=\"wp-block-heading\">Ataques a la Cadena de Suministro<\/h3>\n<p>Un atacante que puede ejecutar c\u00f3digo arbitrario durante un build puede modificar los artefactos de salida. Si el sistema de archivos es escribible sin restricciones, los binarios compilados, las im\u00e1genes de contenedores o los manifiestos de despliegue pueden ser alterados despu\u00e9s del paso leg\u00edtimo de build pero antes de que el artefacto sea enviado. Esta es la esencia de muchos ataques a la cadena de suministro \u2014 el c\u00f3digo fuente parece limpio, pero el artefacto entregado est\u00e1 envenenado.<\/p>\n<h3 class=\"wp-block-heading\">Movimiento Lateral<\/h3>\n<p>Los entornos de build que comparten red con otra infraestructura (bases de datos, APIs internas, servicios de metadatos en la nube) proporcionan al atacante un punto de pivote. Un job de build comprometido puede escanear redes internas, acceder a endpoints de metadatos de instancias en la nube (como <code>169.254.169.254<\/code>) y escalar desde un contexto CI\/CD hacia un acceso m\u00e1s amplio a la infraestructura.<\/p>\n<h2 class=\"wp-block-heading\">Restricciones de Red<\/h2>\n<p>El control m\u00e1s impactante que puedes implementar es restringir el acceso de red saliente desde los entornos de build. Los builds necesitan descargar dependencias y enviar artefactos \u2014 pero raramente necesitan acceso irrestricto a internet.<\/p>\n<h3 class=\"wp-block-heading\">Kubernetes NetworkPolicy para Pods de Runners<\/h3>\n<p>Si ejecutas runners CI\/CD en Kubernetes (por ejemplo, usando Actions Runner Controller o el executor de Kubernetes de GitLab), los recursos NetworkPolicy te ofrecen un control granular sobre el acceso de red a nivel de pod. Una pol\u00edtica bien dise\u00f1ada deniega todo el tr\u00e1fico de salida por defecto y luego permite solo los endpoints espec\u00edficos que el build necesita.<\/p>\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<p>Esta pol\u00edtica permite que los pods de runners resuelvan DNS, accedan al registry de contenedores y al almacenamiento de artefactos \u2014 nada m\u00e1s. Cualquier otra conexi\u00f3n saliente es descartada. Si utilizas un plugin CNI que soporta NetworkPolicy (Calico, Cilium o Weave Net), esto entra en vigor inmediatamente al aplicarse.<\/p>\n<p>Para un control m\u00e1s granular, la <code>CiliumNetworkPolicy<\/code> de Cilium soporta reglas basadas en DNS, permiti\u00e9ndote especificar nombres de dominio en lugar de bloques de IP:<\/p>\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<h3 class=\"wp-block-heading\">Docker &#8211;network=none<\/h3>\n<p>Para pasos de build basados en Docker que no deber\u00edan necesitar acceso de red (compilaci\u00f3n, an\u00e1lisis est\u00e1tico, tests unitarios), puedes eliminar el acceso de red por completo ejecutando el contenedor con <code>--network=none<\/code>:<\/p>\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<p>Con <code>--network=none<\/code>, el contenedor no tiene interfaces de red en absoluto \u2014 ni siquiera loopback en algunas configuraciones. Este es el aislamiento de red m\u00e1s fuerte que puedes lograr para un paso de build. La clave es estructurar tu pipeline de manera que la obtenci\u00f3n de dependencias ocurra en una etapa (con acceso de red limitado) y el build real ocurra en una etapa separada sin red.<\/p>\n<h3 class=\"wp-block-heading\">Reglas de Firewall para Runners Self-Hosted<\/h3>\n<p>Si utilizas runners self-hosted en VMs en lugar de contenedores, las reglas de firewall a nivel de host proporcionan una protecci\u00f3n equivalente. En Linux, las reglas de <code>iptables<\/code> o <code>nftables<\/code> pueden restringir el tr\u00e1fico saliente de la cuenta de usuario que ejecuta los jobs de CI:<\/p>\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<p>Este enfoque funciona bien cuando ejecutas el agente de CI bajo una cuenta de usuario dedicada y necesitas permitir que el sistema host mantenga una conectividad m\u00e1s amplia para gesti\u00f3n y actualizaciones.<\/p>\n<h3 class=\"wp-block-heading\">Allowlisting de Registries y APIs<\/h3>\n<p>Independientemente del mecanismo de aplicaci\u00f3n, el principio es el mismo: denegar por defecto el tr\u00e1fico saliente y luego permitir solo lo que el build realmente necesita. Una lista de permitidos t\u00edpica incluye el registry de paquetes (npm, PyPI, Maven Central), el registry de contenedores (Docker Hub, GHCR, ECR), la API de la plataforma CI\/CD (para actualizaciones de estado y subida de artefactos), y posiblemente un proxy o mirror que t\u00fa controles. Todo lo dem\u00e1s debe ser bloqueado. Usa un proxy interno o mirror para dependencias siempre que sea posible \u2014 reduce la lista de permitidos a un solo endpoint y te proporciona cach\u00e9 y registro de auditor\u00eda de forma gratuita.<\/p>\n<h2 class=\"wp-block-heading\">Restricciones del Sistema de Archivos<\/h2>\n<p>Las restricciones de red evitan que los datos salgan del entorno de build. Las restricciones del sistema de archivos evitan modificaciones no autorizadas dentro de \u00e9l. Juntas, forman una s\u00f3lida postura de defensa en profundidad.<\/p>\n<h3 class=\"wp-block-heading\">Sistema de Archivos Ra\u00edz de Solo Lectura<\/h3>\n<p>Ejecutar contenedores de build con un sistema de archivos ra\u00edz de solo lectura impide que cualquier proceso modifique la imagen base. Esto bloquea una clase de ataques en los que el c\u00f3digo malicioso modifica binarios del sistema, instala backdoors o altera las configuraciones de las herramientas de build a nivel de sistema.<\/p>\n<p>En Docker, usa el flag <code>--read-only<\/code>:<\/p>\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<p>En Kubernetes, establece el security context en la especificaci\u00f3n del pod:<\/p>\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<h3 class=\"wp-block-heading\">tmpfs para Artefactos de Build<\/h3>\n<p>Cuando el sistema de archivos ra\u00edz es de solo lectura, los builds necesitan espacio escribible para archivos temporales, cach\u00e9s y artefactos de salida. Usa montajes <code>tmpfs<\/code> (respaldados por RAM) o vol\u00famenes <code>emptyDir<\/code> (en Kubernetes) para estas rutas. Esto tiene el beneficio adicional de que todos los artefactos de build se limpian autom\u00e1ticamente cuando el contenedor finaliza \u2014 no persisten datos obsoletos entre builds.<\/p>\n<p>Monta <code>tmpfs<\/code> con opciones restrictivas siempre que sea posible: <code>noexec<\/code> previene la ejecuci\u00f3n de binarios escritos en directorios temporales (bloqueando un vector de ataque com\u00fan), <code>nosuid<\/code> previene ataques de bit SUID, y <code>size<\/code> limita para evitar que un build descontrolado agote la memoria del host.<\/p>\n<h3 class=\"wp-block-heading\">Prevenci\u00f3n de Escrituras en Rutas Sensibles<\/h3>\n<p>M\u00e1s all\u00e1 del sistema de archivos ra\u00edz, ciertas rutas espec\u00edficas merecen protecci\u00f3n adicional. Monta el c\u00f3digo fuente como solo lectura para evitar que el build modifique sus propias entradas. Aseg\u00farate de que <code>\/etc<\/code>, <code>\/usr<\/code> y <code>\/var<\/code> no sean escribibles. Si el build necesita escribir en un directorio home (para configuraci\u00f3n de herramientas), proporciona un montaje escribible dedicado en lugar de hacer todo el directorio home escribible. Bloquea el acceso a sockets de Docker, tokens de service account de Kubernetes y archivos de credenciales en la nube no mont\u00e1ndolos en los contenedores de build en absoluto.<\/p>\n<h2 class=\"wp-block-heading\">Builds Herm\u00e9ticos<\/h2>\n<p>El est\u00e1ndar de oro para la seguridad de entornos de build es el build herm\u00e9tico: un build que no tiene acceso de red en absoluto y utiliza solo entradas expl\u00edcitamente declaradas y pre-obtenidas. Los builds herm\u00e9ticos eliminan clases enteras de ataques a la cadena de suministro porque el proceso de build no puede descargar c\u00f3digo que no fue expl\u00edcitamente especificado y verificado.<\/p>\n<h3 class=\"wp-block-heading\">El Patr\u00f3n de Build Herm\u00e9tico<\/h3>\n<p>Un pipeline de build herm\u00e9tico t\u00edpicamente tiene dos fases. En la primera fase (la fase de resoluci\u00f3n\/obtenci\u00f3n), las dependencias se descargan de fuentes aprobadas, sus checksums se verifican contra un lockfile y se almacenan en una cach\u00e9 local o directorio vendorizado. Esta fase requiere acceso de red limitado. En la segunda fase (la fase de build), la compilaci\u00f3n o ensamblaje real ocurre con cero acceso de red. Todas las entradas provienen del sistema de archivos local \u2014 c\u00f3digo fuente y las dependencias pre-obtenidas.<\/p>\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<h3 class=\"wp-block-heading\">Bazel y Builds Herm\u00e9ticos<\/h3>\n<p>Bazel est\u00e1 dise\u00f1ado en torno a la hermeticidad. Con <code>--sandbox_default_allow_network=false<\/code>, Bazel bloquea el acceso de red durante las acciones de build por defecto. Las dependencias se declaran en archivos <code>WORKSPACE<\/code> o <code>MODULE.bazel<\/code> con hashes SHA-256 expl\u00edcitos, y Bazel las obtiene en una fase separada antes de que el build comience. Si una dependencia no coincide con su hash declarado, el build falla.<\/p>\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<p>Esto hace que los builds de Bazel sean reproducibles y resistentes a ataques de confusi\u00f3n de dependencias. Cada entrada est\u00e1 direccionada por contenido y verificada.<\/p>\n<h3 class=\"wp-block-heading\">Nix y Builds Reproducibles<\/h3>\n<p>Nix adopta un enfoque similar. Cada derivaci\u00f3n de build especifica sus entradas por hash de contenido, y el sandbox de build de Nix bloquea el acceso de red por defecto. El comando <code>nix-build<\/code> obtiene todas las fuentes en el Nix store (verificando hashes), luego ejecuta el build en un entorno aislado sin red y con un sistema de archivos m\u00ednimo. Esto garantiza que los builds sean reproducibles \u2014 las mismas entradas siempre producen la misma salida.<\/p>\n<h2 class=\"wp-block-heading\">Implementaci\u00f3n Pr\u00e1ctica<\/h2>\n<p>Veamos c\u00f3mo implementar estas restricciones en plataformas CI\/CD espec\u00edficas.<\/p>\n<h3 class=\"wp-block-heading\">GitHub Actions con Actions Runner Controller (ARC) + NetworkPolicy<\/h3>\n<p>Si utilizas <a href=\"https:\/\/secure-pipelines.com\/ci-cd-security\/lab-ephemeral-self-hosted-runners-actions-runner-controller\/\">Actions Runner Controller<\/a> para ejecutar GitHub Actions en Kubernetes, puedes aplicar NetworkPolicies directamente a los pods de runners. ARC crea pods con labels predecibles, lo que facilita dirigirlos con pol\u00edticas.<\/p>\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<p>Esta configuraci\u00f3n deniega todo el tr\u00e1fico de entrada (los runners no deber\u00edan aceptar conexiones entrantes) y limita el tr\u00e1fico de salida a DNS y HTTPS. Para uso en producci\u00f3n, reemplaza el CIDR <code>0.0.0.0\/0<\/code> con rangos de IP espec\u00edficos para la API de GitHub, tu registry de contenedores y tu almacenamiento de artefactos.<\/p>\n<h3 class=\"wp-block-heading\">GitLab CI con Configuraci\u00f3n de Runner<\/h3>\n<p>El executor de Kubernetes de GitLab soporta la configuraci\u00f3n de security context en el <code>config.toml<\/code> del runner. Puedes establecer el sistema de archivos de solo lectura y otras restricciones directamente:<\/p>\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<p>Combina esto con una NetworkPolicy aplicada al namespace <code>ci-runners<\/code> y tendr\u00e1s tanto las restricciones del sistema de archivos como las de red en su lugar.<\/p>\n<h3 class=\"wp-block-heading\">Restricciones de Docker-in-Docker<\/h3>\n<p>Docker-in-Docker (DinD) se usa com\u00fanmente para construir im\u00e1genes de contenedores en CI. Tambi\u00e9n es uno de los patrones m\u00e1s riesgosos porque t\u00edpicamente requiere modo privilegiado. Si debes usar DinD, aplica estas restricciones:<\/p>\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<p>Mejor a\u00fan, reemplaza DinD con herramientas que no necesiten un daemon de Docker en absoluto. <code>kaniko<\/code>, <code>buildah<\/code> y <code>ko<\/code> pueden construir im\u00e1genes de contenedores sin acceso privilegiado, y funcionan bien con sistemas de archivos de solo lectura y redes restringidas.<\/p>\n<h2 class=\"wp-block-heading\">Monitoreo y Auditor\u00eda<\/h2>\n<p>Las restricciones solo son \u00fatiles si sabes cu\u00e1ndo est\u00e1n siendo probadas o evadidas. El monitoreo completa el panorama de seguridad.<\/p>\n<h3 class=\"wp-block-heading\">Detecci\u00f3n de Conexiones de Red Inesperadas<\/h3>\n<p>Usa Hubble de Cilium, los logs de flujo de Calico o Falco para detectar conexiones de red que tu pol\u00edtica deber\u00eda haber bloqueado (o conexiones a destinos inusuales en puertos permitidos). Configura alertas para cualquier consulta DNS a dominios que no est\u00e9n en tu lista de permitidos, conexiones salientes a puertos no est\u00e1ndar, conexiones a rangos de IP conocidos como maliciosos y cualquier tr\u00e1fico de salida desde pods que deber\u00edan tener <code>--network=none<\/code>.<\/p>\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<h3 class=\"wp-block-heading\">Auditor\u00eda de Acceso al Sistema de Archivos<\/h3>\n<p>Monitorea las escrituras en el sistema de archivos dentro de los contenedores de build para detectar modificaciones inesperadas. El <code>auditd<\/code> de Linux puede vigilar rutas espec\u00edficas, y Falco puede detectar escrituras en ubicaciones sensibles. Las rutas clave a monitorear incluyen <code>\/etc<\/code> y <code>\/usr<\/code> (nunca deber\u00edan ser escritas en un build), la ruta del socket de Docker, las rutas de tokens de service account de Kubernetes y cualquier ruta que contenga credenciales o claves de firma.<\/p>\n<p>Si usas sistemas de archivos ra\u00edz de solo lectura, cualquier intento de escritura en una ruta protegida genera un error \u2014 registra estos errores y genera alertas sobre ellos. Indican ya sea un build mal configurado o un posible ataque.<\/p>\n<h2 class=\"wp-block-heading\">Compromisos y Experiencia del Desarrollador<\/h2>\n<p>Las restricciones estrictas de red y sistema de archivos inevitablemente generan fricci\u00f3n. Comprender y gestionar los compromisos es fundamental para una adopci\u00f3n exitosa.<\/p>\n<h3 class=\"wp-block-heading\">Velocidad de Build<\/h3>\n<p>Los builds herm\u00e9ticos requieren que todas las dependencias sean pre-obtenidas, lo que a\u00f1ade una etapa al pipeline. Sin embargo, esto tambi\u00e9n significa que las dependencias pueden ser cacheadas agresivamente. En la pr\u00e1ctica, muchos equipos encuentran que los builds herm\u00e9ticos son en realidad m\u00e1s r\u00e1pidos porque la tasa de aciertos de cach\u00e9 es mucho mayor cuando la resoluci\u00f3n de dependencias es determinista. Usa una cach\u00e9 compartida (una remote cache de Bazel, una binary cache de Nix o una simple cach\u00e9 HTTP para dependencias vendorizadas) para amortizar el costo entre builds.<\/p>\n<h3 class=\"wp-block-heading\">Experiencia del Desarrollador<\/h3>\n<p>Los desarrolladores encontrar\u00e1n fallos cuando los builds intenten acceder a endpoints de red bloqueados o escribir en rutas de solo lectura. Los buenos mensajes de error son esenciales. Envuelve tus pasos de build en scripts que capturen errores de permisos y fallos de red, luego muestra mensajes accionables que expliquen por qu\u00e9 el acceso fue bloqueado y c\u00f3mo solucionar el problema (generalmente agregando una dependencia al lockfile o cambiando la ruta de salida).<\/p>\n<p>Considera implementar un despliegue gradual: comienza con modo de monitoreo (registra violaciones pero no las bloquea), luego pasa a la aplicaci\u00f3n. Esto da tiempo a los equipos para actualizar sus configuraciones de build sin romper todos los pipelines de una vez.<\/p>\n<h3 class=\"wp-block-heading\">Depuraci\u00f3n<\/h3>\n<p>Depurar fallos de build en un entorno restringido es m\u00e1s dif\u00edcil cuando no puedes instalar herramientas adicionales ni acceder a servicios externos. Proporciona un \u00abmodo de depuraci\u00f3n\u00bb que relaje las restricciones para una ejecuci\u00f3n de pipeline espec\u00edfica, activada manualmente (nunca para ejecuciones automatizadas en la rama principal). Registra que se us\u00f3 el modo de depuraci\u00f3n y qui\u00e9n lo activ\u00f3. Nunca permitas que el modo de depuraci\u00f3n evite las restricciones en builds de artefactos de producci\u00f3n.<\/p>\n<h2 class=\"wp-block-heading\">Integrando Todo<\/h2>\n<p>Aqu\u00ed hay un resumen del enfoque por capas para asegurar los entornos de build CI\/CD:<\/p>\n<p><strong>Capa 1 \u2014 Restricciones de red:<\/strong> Denegaci\u00f3n por defecto del tr\u00e1fico de salida con listas de permitidos para registries y APIs. Usa Kubernetes NetworkPolicy, Docker <code>--network=none<\/code> o reglas de firewall a nivel de host seg\u00fan tu infraestructura de runners.<\/p>\n<p><strong>Capa 2 \u2014 Restricciones del sistema de archivos:<\/strong> Sistema de archivos ra\u00edz de solo lectura, tmpfs para rutas escribibles con l\u00edmites de tama\u00f1o y noexec, c\u00f3digo fuente montado como solo lectura.<\/p>\n<p><strong>Capa 3 \u2014 Builds herm\u00e9ticos:<\/strong> Separar la resoluci\u00f3n de dependencias del build. Ejecutar la fase de build con cero acceso de red y solo entradas pre-obtenidas y verificadas por hash.<\/p>\n<p><strong>Capa 4 \u2014 Monitoreo:<\/strong> Detectar y alertar sobre violaciones de pol\u00edticas, conexiones inesperadas e intentos de modificaci\u00f3n del sistema de archivos.<\/p>\n<p>Ninguna capa es suficiente por s\u00ed sola. Las restricciones de red sin controles del sistema de archivos a\u00fan permiten la alteraci\u00f3n de artefactos. Las restricciones del sistema de archivos sin controles de red a\u00fan permiten la exfiltraci\u00f3n. Los builds herm\u00e9ticos sin monitoreo te dejan ciego ante intentos de ataque. Las capas se refuerzan mutuamente.<\/p>\n<h2 class=\"wp-block-heading\">Gu\u00edas Relacionadas<\/h2>\n<p>Para m\u00e1s informaci\u00f3n sobre c\u00f3mo asegurar tu pipeline CI\/CD, consulta estas gu\u00edas relacionadas:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/secure-pipelines.com\/es\/?p=646\">Integridad de Build y Builds Reproducibles en CI\/CD<\/a> \u2014 cubre cumplimiento SLSA, verificaci\u00f3n de builds reproducibles y procedencia de artefactos.<\/li>\n<li><a href=\"https:\/\/secure-pipelines.com\/ci-cd-security\/lab-ephemeral-self-hosted-runners-actions-runner-controller\/\">Lab: Runners Self-Hosted Ef\u00edmeros con Actions Runner Controller<\/a> \u2014 gu\u00eda pr\u00e1ctica para desplegar ARC en Kubernetes con pods de runners ef\u00edmeros y de un solo uso.<\/li>\n<\/ul>\n<p>Comienza con las restricciones de red \u2014 ofrecen el mayor impacto con el menor esfuerzo de implementaci\u00f3n. Luego a\u00f1ade restricciones del sistema de archivos y avanza hacia builds herm\u00e9ticos a medida que la madurez de tu pipeline aumente. Cada capa que a\u00f1adas hace que los ataques a la cadena de suministro sean significativamente m\u00e1s dif\u00edciles de ejecutar.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Los pipelines CI\/CD se encuentran entre las cargas de trabajo m\u00e1s privilegiadas de cualquier organizaci\u00f3n. Extraen c\u00f3digo fuente, descargan dependencias, acceden a secrets y env\u00edan artefactos a registries de producci\u00f3n. Sin embargo, en muchos entornos, los procesos de build detr\u00e1s de estos pipelines se ejecutan con acceso de red sin restricciones y permisos completos sobre &#8230; <a title=\"Restricciones de Red y Sistema de Archivos para Entornos de Build CI\/CD\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/network-filesystem-restrictions-ci-cd-build-environments\/\" aria-label=\"Leer m\u00e1s sobre Restricciones de Red y Sistema de Archivos para Entornos de Build CI\/CD\">Leer m\u00e1s<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55,58],"tags":[],"post_folder":[],"class_list":["post-643","post","type-post","status-publish","format-standard","hentry","category-ci-cd-security","category-pipeline-hardening"],"_links":{"self":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/643","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/comments?post=643"}],"version-history":[{"count":2,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/643\/revisions"}],"predecessor-version":[{"id":681,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/643\/revisions\/681"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/media?parent=643"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/categories?post=643"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/tags?post=643"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/post_folder?post=643"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}