{"id":642,"date":"2026-03-02T01:06:45","date_gmt":"2026-03-02T00:06:45","guid":{"rendered":"https:\/\/secure-pipelines.com\/?p=642"},"modified":"2026-03-24T18:08:02","modified_gmt":"2026-03-24T17:08:02","slug":"separation-of-duties-least-privilege-ci-cd-pipelines","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/separation-of-duties-least-privilege-ci-cd-pipelines\/","title":{"rendered":"Separaci\u00f3n de Responsabilidades y M\u00ednimo Privilegio en Pipelines CI\/CD"},"content":{"rendered":"<h2>Introducci\u00f3n<\/h2>\n<p>La mayor\u00eda de los pipelines CI\/CD comienzan con un objetivo simple: llevar el c\u00f3digo desde la m\u00e1quina de un desarrollador a producci\u00f3n lo m\u00e1s r\u00e1pido posible. En el camino, alguien crea una cuenta de servicio, le otorga permisos amplios, almacena las credenciales como un secreto del pipeline y sigue adelante. Funciona. Los builds pasan, los despliegues tienen \u00e9xito y nadie vuelve a pensar en ello \u2014 hasta que un atacante compromete ese pipeline y descubre que tiene las llaves de todo el reino.<\/p>\n<p>El problema no es que los equipos sean descuidados. El problema es que las herramientas CI\/CD hacen que sea <em>f\u00e1cil<\/em> otorgar privilegios excesivos y <em>dif\u00edcil<\/em> aplicar controles granulares. La ruta predeterminada en la mayor\u00eda de las plataformas es una identidad \u00fanica con acceso amplio ejecutando cada etapa del pipeline. Principios de seguridad como la <strong>separaci\u00f3n de responsabilidades<\/strong> (SoD) y el <strong>m\u00ednimo privilegio<\/strong> parecen una carga burocr\u00e1tica cuando est\u00e1s intentando entregar funcionalidades.<\/p>\n<p>No lo son. Son controles de ingenier\u00eda que limitan el radio de impacto cuando \u2014 no si \u2014 algo sale mal. Esta gu\u00eda explica c\u00f3mo aplicar ambos principios a los pipelines CI\/CD de una manera que fortalezca su postura de seguridad sin destruir la velocidad de entrega.<\/p>\n<h2>Por Qu\u00e9 los Pipelines Acumulan Privilegios<\/h2>\n<p>Antes de profundizar en las soluciones, vale la pena entender c\u00f3mo los pipelines terminan con permisos excesivos en primer lugar. El patr\u00f3n es notablemente consistente entre organizaciones.<\/p>\n<h3>El problema de la cuenta de servicio \u00fanica<\/h3>\n<p>Comienza con una \u00fanica cuenta de servicio \u2014 a menudo nombrada algo como <code>ci-deployer<\/code> o <code>pipeline-bot<\/code> \u2014 que se crea durante la configuraci\u00f3n inicial del CI\/CD. Esta cuenta necesita obtener c\u00f3digo, as\u00ed que recibe acceso de lectura al repositorio. Luego necesita subir im\u00e1genes Docker, as\u00ed que recibe acceso de escritura al registro. Luego necesita desplegar en staging, luego en producci\u00f3n, luego gestionar infraestructura. En semanas, esta \u00fanica identidad puede construir, probar, desplegar y acceder a datos de producci\u00f3n. Se ha convertido en una llave maestra.<\/p>\n<h3>God tokens<\/h3>\n<p>Estrechamente relacionado est\u00e1 el \u00abgod token\u00bb \u2014 un token de acceso personal o clave API con acceso de lectura\/escritura a todo. Estos tokens a menudo son creados por un administrador durante la configuraci\u00f3n, almacenados como una variable CI\/CD y nunca rotados. T\u00edpicamente sobreviven a la persona que los cre\u00f3, y nadie recuerda exactamente qu\u00e9 permisos tienen.<\/p>\n<h3>Conveniencia sobre seguridad<\/h3>\n<p>Las organizaciones frecuentemente usan un \u00fanico pool de runners para todos los entornos. La misma m\u00e1quina que ejecuta pruebas unitarias en pull requests no confiables de forks tambi\u00e9n tiene acceso de red a la infraestructura de producci\u00f3n. El razonamiento es directo: mantener pools de runners separados es operacionalmente costoso. Pero esta conveniencia significa que un pull request malicioso podr\u00eda potencialmente acceder a credenciales de producci\u00f3n.<\/p>\n<h3>Falta de l\u00edmites de identidad entre etapas<\/h3>\n<p>La mayor\u00eda de los pipelines ejecutan todas las etapas bajo la misma identidad. La etapa de build, la etapa de test, la etapa de deploy \u2014 todas comparten la misma cuenta de servicio, los mismos secretos y el mismo acceso de red. No hay l\u00edmite entre \u00abcompilar c\u00f3digo\u00bb y \u00absubir a producci\u00f3n\u00bb. Desde una perspectiva de seguridad, estos son niveles de confianza fundamentalmente diferentes que nunca deber\u00edan compartir una identidad.<\/p>\n<h2>Separaci\u00f3n de Responsabilidades en CI\/CD<\/h2>\n<p>La separaci\u00f3n de responsabilidades es un principio de dise\u00f1o de controles que asegura que ninguna entidad \u00fanica tenga suficiente acceso para completar un proceso cr\u00edtico por s\u00ed sola. En CI\/CD, esto significa dividir deliberadamente las operaciones del pipeline entre diferentes identidades, aprobaciones y l\u00edmites de confianza.<\/p>\n<h3>Principios fundamentales para SoD en pipelines<\/h3>\n<ul>\n<li><strong>Ninguna identidad \u00fanica deber\u00eda construir Y desplegar en producci\u00f3n.<\/strong> La identidad que compila c\u00f3digo y produce artefactos no deber\u00eda ser la misma identidad que sube esos artefactos a la infraestructura de producci\u00f3n.<\/li>\n<li><strong>Los autores de c\u00f3digo no deber\u00edan aprobar sus propios despliegues.<\/strong> La persona que escribe c\u00f3digo no deber\u00eda ser la \u00fanica aprobadora de que ese c\u00f3digo llegue a producci\u00f3n. Como m\u00ednimo, debe estar involucrado un segundo humano.<\/li>\n<li><strong>Las definiciones del pipeline deber\u00edan estar protegidas del c\u00f3digo que procesan.<\/strong> Los archivos de workflow que definen c\u00f3mo se construye y despliega el c\u00f3digo no deber\u00edan ser modificables por el mismo proceso que ejecuta el c\u00f3digo de la aplicaci\u00f3n.<\/li>\n<li><strong>Los artefactos de build deber\u00edan ser inmutables una vez producidos.<\/strong> Una vez que una etapa de build produce un artefacto, ninguna etapa posterior deber\u00eda poder modificarlo. El artefacto que fue probado es el artefacto que se despliega.<\/li>\n<\/ul>\n<h3>Mapeando SoD a las etapas del pipeline<\/h3>\n<p>Un pipeline bien dise\u00f1ado mapea la separaci\u00f3n de responsabilidades a etapas discretas, cada una con su propia identidad y permisos:<\/p>\n<ul>\n<li><strong>Build<\/strong> \u2014 Compila c\u00f3digo, resuelve dependencias, produce artefactos. Requiere acceso de lectura al c\u00f3digo fuente y registros de dependencias. Sin acceso a objetivos de despliegue.<\/li>\n<li><strong>Test<\/strong> \u2014 Ejecuta pruebas unitarias, pruebas de integraci\u00f3n, escaneos de seguridad. Requiere acceso de lectura a artefactos e infraestructura de pruebas. Sin acceso a secretos de producci\u00f3n.<\/li>\n<li><strong>Sign<\/strong> \u2014 Firma criptogr\u00e1ficamente los artefactos que pasan todas las verificaciones. Requiere acceso a las claves de firma pero nada m\u00e1s. Esta etapa act\u00faa como una puerta de control.<\/li>\n<li><strong>Stage<\/strong> \u2014 Despliega en un entorno de staging para validaci\u00f3n final. Requiere acceso de escritura solo a staging. Sin credenciales de producci\u00f3n disponibles.<\/li>\n<li><strong>Deploy<\/strong> \u2014 Promueve el artefacto firmado y probado a producci\u00f3n. Requiere acceso de escritura a producci\u00f3n, controlado por aprobaci\u00f3n manual. Identidad diferente a la de build.<\/li>\n<\/ul>\n<p>Cada l\u00edmite de etapa es un l\u00edmite de confianza. Las credenciales no fluyen entre etapas a menos que se otorguen expl\u00edcitamente.<\/p>\n<h2>Patrones de M\u00ednimo Privilegio<\/h2>\n<p>El m\u00ednimo privilegio significa otorgar solo los permisos m\u00ednimos requeridos para una tarea espec\u00edfica, durante el menor tiempo necesario. En CI\/CD, esto se traduce en patrones concretos que var\u00edan seg\u00fan la plataforma.<\/p>\n<h3>GitHub Actions: permisos por job<\/h3>\n<p>GitHub Actions proporciona un bloque <code>permissions<\/code> que controla los alcances del <code>GITHUB_TOKEN<\/code> generado autom\u00e1ticamente. Por defecto, este token tiene acceso amplio de lectura\/escritura. Siempre deber\u00edas restringirlo.<\/p>\n<p>Establece valores predeterminados restrictivos a nivel de workflow y otorga permisos adicionales solo a los jobs espec\u00edficos que los necesiten:<\/p>\n<pre><code># .github\/workflows\/deploy.yml\nname: Build and Deploy\n\n# Restrict default permissions for ALL jobs in this workflow\npermissions:\n  contents: read\n\non:\n  push:\n    branches: [main]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    # This job inherits the workflow-level permissions: contents read only\n    steps:\n      - uses: actions\/checkout@v4\n      - run: make build\n      - uses: actions\/upload-artifact@v4\n        with:\n          name: app-binary\n          path: dist\/\n\n  security-scan:\n    needs: build\n    runs-on: ubuntu-latest\n    permissions:\n      security-events: write  # Only this job can write security findings\n      contents: read\n    steps:\n      - uses: actions\/checkout@v4\n      - uses: github\/codeql-action\/analyze@v3\n\n  deploy-staging:\n    needs: [build, security-scan]\n    runs-on: ubuntu-latest\n    environment: staging  # Scoped to staging secrets only\n    permissions:\n      contents: read\n      id-token: write  # OIDC token for cloud auth \u2014 no static credentials\n    steps:\n      - uses: aws-actions\/configure-aws-credentials@v4\n        with:\n          role-to-assume: arn:aws:iam::123456789:role\/staging-deployer\n          aws-region: us-east-1\n      - run: .\/scripts\/deploy.sh staging\n\n  deploy-production:\n    needs: deploy-staging\n    runs-on: ubuntu-latest\n    environment: production  # Requires manual approval + different secrets\n    permissions:\n      contents: read\n      id-token: write\n    steps:\n      - uses: aws-actions\/configure-aws-credentials@v4\n        with:\n          role-to-assume: arn:aws:iam::123456789:role\/production-deployer\n          aws-region: us-east-1\n      - run: .\/scripts\/deploy.sh production<\/code><\/pre>\n<p>Puntos clave en esta configuraci\u00f3n: cada job declara solo los permisos que necesita, los jobs de despliegue usan OIDC para credenciales de corta duraci\u00f3n en lugar de secretos est\u00e1ticos, y staging y producci\u00f3n usan roles IAM diferentes con distintos niveles de acceso.<\/p>\n<h3>GitLab CI: variables protegidas y runners<\/h3>\n<p>GitLab CI ofrece un conjunto diferente pero igualmente poderoso de controles para implementar el m\u00ednimo privilegio:<\/p>\n<pre><code># .gitlab-ci.yml\nstages:\n  - build\n  - test\n  - deploy-staging\n  - deploy-production\n\nbuild:\n  stage: build\n  tags:\n    - shared-runners  # Non-privileged runners for build\n  script:\n    - make build\n  artifacts:\n    paths:\n      - dist\/\n\ntest:\n  stage: test\n  tags:\n    - shared-runners\n  script:\n    - make test\n  dependencies:\n    - build\n\ndeploy-staging:\n  stage: deploy-staging\n  tags:\n    - deploy-runners  # Dedicated runners with network access to staging\n  environment:\n    name: staging\n  script:\n    - .\/scripts\/deploy.sh staging\n  # CI_JOB_TOKEN is automatically scoped to this project\n  # Staging secrets are only available on protected branches\n  rules:\n    - if: '$CI_COMMIT_BRANCH == \"main\"'\n\ndeploy-production:\n  stage: deploy-production\n  tags:\n    - production-runners  # Isolated runners with production network access\n  environment:\n    name: production\n  script:\n    - .\/scripts\/deploy.sh production\n  rules:\n    - if: '$CI_COMMIT_BRANCH == \"main\"'\n      when: manual  # Requires manual approval\n  allow_failure: false  # Block the pipeline if not approved<\/code><\/pre>\n<p>En GitLab, use <strong>variables protegidas<\/strong> para que las credenciales de producci\u00f3n solo est\u00e9n disponibles para ramas y tags protegidos. Use <strong>runners protegidos<\/strong> para asegurar que los jobs de despliegue a producci\u00f3n solo se ejecuten en infraestructura aislada y reforzada. Marque los secretos de producci\u00f3n como <strong>enmascarados<\/strong> para prevenir la exposici\u00f3n accidental en los logs.<\/p>\n<h3>Cuentas de servicio por etapa con roles IAM delimitados<\/h3>\n<p>M\u00e1s all\u00e1 de la plataforma CI en s\u00ed, aplique el m\u00ednimo privilegio a nivel del proveedor de nube. Cada etapa del pipeline deber\u00eda autenticarse como una cuenta de servicio diferente con permisos estrictamente delimitados:<\/p>\n<ul>\n<li><strong>Etapa de build:<\/strong> Acceso de solo lectura a repositorios de c\u00f3digo fuente y registros de dependencias. Acceso de escritura al almac\u00e9n de artefactos (por ejemplo, bucket S3, registro de contenedores) pero nada m\u00e1s.<\/li>\n<li><strong>Etapa de test:<\/strong> Acceso de solo lectura a artefactos. Permiso para crear y destruir infraestructura de pruebas ef\u00edmera, pero sin acceso a staging o producci\u00f3n.<\/li>\n<li><strong>Etapa de deploy:<\/strong> Acceso de escritura al objetivo de despliegue espec\u00edfico (por ejemplo, un namespace de Kubernetes espec\u00edfico, un servicio ECS espec\u00edfico). Sin acceso a otros entornos o servicios.<\/li>\n<\/ul>\n<h3>Credenciales de corta duraci\u00f3n v\u00eda OIDC<\/h3>\n<p>Las credenciales est\u00e1ticas almacenadas como secretos CI\/CD son un riesgo. No expiran, son dif\u00edciles de rotar y son objetivos atractivos para los atacantes. El enfoque moderno es usar federaci\u00f3n OIDC para que su plataforma CI\/CD intercambie un token de corta duraci\u00f3n firmado por la plataforma por credenciales temporales en la nube:<\/p>\n<ul>\n<li>GitHub Actions puede asumir roles IAM de AWS, cuentas de servicio de GCP o identidades administradas de Azure usando el permiso <code>id-token: write<\/code> \u2014 sin necesidad de secretos almacenados.<\/li>\n<li>GitLab CI soporta OIDC nativamente a trav\u00e9s de su <code>CI_JOB_JWT<\/code> o la palabra clave <code>id_tokens<\/code>, permitiendo el mismo patr\u00f3n.<\/li>\n<li>Estas credenciales t\u00edpicamente duran de 15 a 60 minutos y est\u00e1n delimitadas al job espec\u00edfico que las solicit\u00f3.<\/li>\n<\/ul>\n<p>Si todav\u00eda est\u00e1 usando claves de acceso est\u00e1ticas en los secretos de su pipeline, migrar a OIDC deber\u00eda ser una iniciativa de alta prioridad.<\/p>\n<h2>Protecci\u00f3n de las Definiciones del Pipeline<\/h2>\n<p>Pipeline-as-code es poderoso, pero introduce un problema de confianza sutil: si un atacante puede modificar la definici\u00f3n del pipeline, controla c\u00f3mo se construye, prueba y despliega el c\u00f3digo. Proteger los archivos de configuraci\u00f3n del pipeline es tan importante como proteger el c\u00f3digo de la aplicaci\u00f3n en s\u00ed.<\/p>\n<h3>CODEOWNERS para archivos de workflow<\/h3>\n<p>Use un archivo CODEOWNERS para requerir que equipos espec\u00edficos revisen los cambios en la configuraci\u00f3n CI\/CD:<\/p>\n<pre><code># .github\/CODEOWNERS\n\/.github\/workflows\/   @your-org\/platform-security\n\/.gitlab-ci.yml       @your-org\/platform-security\n\/Jenkinsfile          @your-org\/platform-security\n\/terraform\/           @your-org\/infrastructure<\/code><\/pre>\n<p>Esto asegura que nadie pueda modificar las definiciones del pipeline sin la aprobaci\u00f3n del equipo responsable de la seguridad CI\/CD. Combine esto con reglas de protecci\u00f3n de ramas que requieran la aprobaci\u00f3n de CODEOWNERS.<\/p>\n<h3>Protecci\u00f3n de ramas en directorios de configuraci\u00f3n del pipeline<\/h3>\n<p>Aplique reglas de protecci\u00f3n de ramas que prevengan pushes directos a ramas que contienen definiciones de pipeline. Como m\u00ednimo:<\/p>\n<ul>\n<li>Requiera revisiones de pull request antes de fusionar cambios en archivos de workflow.<\/li>\n<li>Requiera que las verificaciones de estado pasen (incluyendo escaneos de seguridad de los propios cambios del workflow).<\/li>\n<li>Deshabilite force pushes a ramas protegidas.<\/li>\n<li>Requiera commits firmados para cambios en la configuraci\u00f3n del pipeline.<\/li>\n<\/ul>\n<h3>Plantillas de pipeline inmutables<\/h3>\n<p>Tanto GitHub Actions como GitLab CI soportan referenciar definiciones de pipeline desde repositorios externos gestionados centralmente:<\/p>\n<p><strong>GitHub Actions reusable workflows:<\/strong><\/p>\n<pre><code># In your repository's workflow, reference a centrally managed template\njobs:\n  deploy:\n    uses: your-org\/shared-workflows\/.github\/workflows\/secure-deploy.yml@v2.1.0\n    with:\n      environment: production\n      artifact-name: app-binary\n    secrets: inherit<\/code><\/pre>\n<p><strong>GitLab CI includes desde repositorios protegidos:<\/strong><\/p>\n<pre><code># .gitlab-ci.yml\ninclude:\n  - project: 'platform-team\/ci-templates'\n    ref: 'v3.0.0'\n    file: '\/templates\/secure-deploy.yml'\n\n# Local jobs can use templates but cannot override protected stages\ndeploy-production:\n  extends: .secure-deploy-template\n  variables:\n    TARGET_ENV: production<\/code><\/pre>\n<p>Al fijar versiones espec\u00edficas (tags o SHA de commits) y restringir qui\u00e9n puede modificar el repositorio de plantillas, se asegura de que los equipos individuales no puedan alterar los controles de seguridad integrados en el proceso de despliegue.<\/p>\n<h3>Previniendo pipelines que se auto-modifican<\/h3>\n<p>Un pipeline nunca deber\u00eda poder modificar su propia definici\u00f3n. Est\u00e9 atento a estos patrones:<\/p>\n<ul>\n<li>Pasos del pipeline que escriben en <code>.github\/workflows\/<\/code> o <code>.gitlab-ci.yml<\/code> y hacen commit de los cambios.<\/li>\n<li>Generaci\u00f3n din\u00e1mica de pipelines que obtiene configuraci\u00f3n de fuentes no confiables.<\/li>\n<li>Variables del pipeline que pueden anular configuraciones cr\u00edticas de seguridad como qu\u00e9 runner usar o en qu\u00e9 entorno desplegar.<\/li>\n<\/ul>\n<p>Si necesita comportamiento din\u00e1mico en el pipeline, use plantillas parametrizadas con un conjunto fijo de entradas permitidas en lugar de permitir la modificaci\u00f3n arbitraria de la l\u00f3gica del pipeline.<\/p>\n<h2>Controles de Despliegue<\/h2>\n<p>Los controles de despliegue son las puertas entre las etapas del pipeline que imponen supervisi\u00f3n humana y cumplimiento de pol\u00edticas. Son donde la separaci\u00f3n de responsabilidades se vuelve tangible.<\/p>\n<h3>Revisores requeridos y aprobaciones manuales<\/h3>\n<p>Los despliegues a producci\u00f3n deber\u00edan requerir aprobaci\u00f3n expl\u00edcita de alguien diferente al autor del c\u00f3digo. Ambas plataformas principales soportan esto nativamente:<\/p>\n<ul>\n<li><strong>GitHub Environments<\/strong> permiten configurar revisores requeridos. Cuando un job de workflow referencia un entorno con reglas de protecci\u00f3n, el pipeline se pausa hasta que un revisor autorizado aprueba.<\/li>\n<li><strong>GitLab Protected Environments<\/strong> restringen qu\u00e9 usuarios o grupos pueden activar despliegues a entornos espec\u00edficos. Combinado con <code>when: manual<\/code>, esto crea una puerta de aprobaci\u00f3n.<\/li>\n<\/ul>\n<h3>GitHub Environments con reglas de protecci\u00f3n<\/h3>\n<p>Los GitHub Environments son un mecanismo poderoso para controles de despliegue. Config\u00farelos con:<\/p>\n<ul>\n<li><strong>Revisores requeridos:<\/strong> Especifique individuos o equipos que deben aprobar antes de que el job se ejecute. Use al menos dos revisores para producci\u00f3n.<\/li>\n<li><strong>Temporizador de espera:<\/strong> Agregue un retraso entre la aprobaci\u00f3n y la ejecuci\u00f3n, dando tiempo para detectar errores o coordinarse con ventanas de cambio.<\/li>\n<li><strong>Ramas de despliegue:<\/strong> Restrinja qu\u00e9 ramas pueden desplegar al entorno. Producci\u00f3n solo deber\u00eda aceptar despliegues desde <code>main<\/code> o <code>release\/*<\/code>.<\/li>\n<li><strong>Secretos de entorno:<\/strong> Almacene credenciales a nivel de entorno, no a nivel de repositorio. Esto asegura que los secretos de staging no est\u00e9n disponibles para los jobs de producci\u00f3n y viceversa.<\/li>\n<\/ul>\n<h3>Congelamiento de despliegues y ventanas de cambio<\/h3>\n<p>Implemente congelamientos de despliegue durante per\u00edodos cr\u00edticos del negocio (por ejemplo, Black Friday, fin de trimestre) mediante:<\/p>\n<ul>\n<li>Uso de reglas de protecci\u00f3n de entornos programadas que bloqueen autom\u00e1ticamente los despliegues durante ventanas definidas.<\/li>\n<li>Requerir aprobaciones adicionales durante per\u00edodos de congelamiento en lugar de bloquear completamente \u2014 las correcciones de emergencia deber\u00edan seguir siendo posibles con supervisi\u00f3n elevada.<\/li>\n<li>Registrar todas las excepciones al congelamiento con fines de auditor\u00eda.<\/li>\n<\/ul>\n<h3>Canary y despliegue progresivo como mecanismo de control<\/h3>\n<p>Las estrategias de despliegue progresivo no son solo una preocupaci\u00f3n de disponibilidad \u2014 son un control de seguridad. Si un artefacto comprometido pasa todas las dem\u00e1s verificaciones, un despliegue canary limita el radio de impacto:<\/p>\n<ul>\n<li>Despliegue al 1-5% del tr\u00e1fico primero con verificaciones de salud automatizadas.<\/li>\n<li>Requiera una segunda aprobaci\u00f3n manual para proceder m\u00e1s all\u00e1 de la etapa canary.<\/li>\n<li>Automatice el rollback si las tasas de error o la latencia superan los umbrales.<\/li>\n<li>Trate la etapa canary como un entorno separado con sus propios requisitos de aprobaci\u00f3n.<\/li>\n<\/ul>\n<h2>Auditor\u00eda y Responsabilidad<\/h2>\n<p>La separaci\u00f3n de responsabilidades y el m\u00ednimo privilegio solo son efectivos si puede verificar que se est\u00e1n siguiendo. La auditor\u00eda y la responsabilidad cierran el ciclo proporcionando evidencia de qui\u00e9n hizo qu\u00e9, cu\u00e1ndo y por qu\u00e9.<\/p>\n<h3>Logs de ejecuci\u00f3n del pipeline como registros de auditor\u00eda<\/h3>\n<p>Las plataformas CI\/CD mantienen logs detallados de cada ejecuci\u00f3n del pipeline. Trate estos logs como datos de auditor\u00eda relevantes para la seguridad:<\/p>\n<ul>\n<li>Retenga los logs del pipeline por al menos 90 d\u00edas (m\u00e1s si su marco de cumplimiento lo requiere).<\/li>\n<li>Exporte los logs a un almac\u00e9n de logs centralizado y resistente a manipulaciones (por ejemplo, SIEM, CloudWatch Logs, o un bucket S3 dedicado con object lock).<\/li>\n<li>Aseg\u00farese de que los logs capturen qu\u00e9 identidad activ\u00f3 el pipeline, qu\u00e9 secretos fueron accedidos (pero no sus valores) y qu\u00e9 aprobaciones fueron otorgadas.<\/li>\n<\/ul>\n<h3>Vinculando despliegues a commits y aprobadores<\/h3>\n<p>Cada despliegue a producci\u00f3n deber\u00eda ser rastreable hasta:<\/p>\n<ul>\n<li>El SHA del commit Git espec\u00edfico que fue desplegado.<\/li>\n<li>El pull request que introdujo el cambio, incluyendo todos los revisores y aprobadores.<\/li>\n<li>El ID de ejecuci\u00f3n del pipeline y la persona que aprob\u00f3 la puerta de despliegue.<\/li>\n<li>El digest del artefacto (SHA de imagen de contenedor, hash del binario) que fue desplegado.<\/li>\n<\/ul>\n<p>Esta cadena de trazabilidad deber\u00eda ser automatizada. Si alguien pregunta \u00abqu\u00e9 est\u00e1 corriendo en producci\u00f3n y qui\u00e9n lo aprob\u00f3\u00bb, la respuesta deber\u00eda estar disponible en segundos, no en horas.<\/p>\n<h3>Logs de auditor\u00eda en la nube para cambios iniciados por el pipeline<\/h3>\n<p>Las acciones del pipeline dejan rastros en los logs de auditor\u00eda del proveedor de nube. Correlacione estos con sus logs CI\/CD:<\/p>\n<ul>\n<li><strong>AWS CloudTrail<\/strong> registra cada llamada API realizada por el rol IAM asumido por su pipeline. Haga referencia cruzada del ID de ejecuci\u00f3n del pipeline con el <code>userIdentity.sessionContext<\/code> de CloudTrail para vincular los cambios en la nube a ejecuciones espec\u00edficas del pipeline.<\/li>\n<li><strong>GCP Cloud Audit Logs<\/strong> proporcionan trazabilidad similar para las acciones de cuentas de servicio.<\/li>\n<li><strong>Azure Activity Logs<\/strong> capturan las modificaciones de recursos realizadas por los service principals del pipeline.<\/li>\n<\/ul>\n<h3>Alertas sobre escalamiento de privilegios o evasi\u00f3n de pol\u00edticas<\/h3>\n<p>Configure alertas para eventos que indiquen que sus controles est\u00e1n siendo eludidos:<\/p>\n<ul>\n<li>Un pipeline accediendo a secretos que no deber\u00eda necesitar (por ejemplo, la etapa de build accediendo a credenciales de base de datos de producci\u00f3n).<\/li>\n<li>Cambios en las reglas de protecci\u00f3n de ramas o archivos CODEOWNERS.<\/li>\n<li>Modificaciones a las pol\u00edticas IAM adjuntas a las cuentas de servicio del pipeline.<\/li>\n<li>Ejecuciones de pipeline activadas desde ramas no protegidas desplegando a entornos protegidos.<\/li>\n<li>Aprobaciones de despliegue otorgadas por la misma persona que escribi\u00f3 el c\u00f3digo.<\/li>\n<\/ul>\n<p>Alimente estas alertas en su flujo de trabajo de operaciones de seguridad y tr\u00e1telas con la misma urgencia que los incidentes de producci\u00f3n.<\/p>\n<h2>Anti-Patrones Comunes<\/h2>\n<p>Saber qu\u00e9 evitar es tan importante como saber qu\u00e9 implementar. Estos son los anti-patrones que vemos con m\u00e1s frecuencia en las evaluaciones de seguridad CI\/CD.<\/p>\n<h3>Token de administrador \u00fanico para todas las operaciones CI\/CD<\/h3>\n<p>Un token de acceso personal con alcance de administrador, creado por un ingeniero senior, almacenado como un secreto del repositorio y usado por cada job en cada pipeline. Cuando ese ingeniero deja la organizaci\u00f3n, nadie revoca el token porque nadie sabe qu\u00e9 se romper\u00e1. Este es el anti-patr\u00f3n m\u00e1s com\u00fan y m\u00e1s peligroso.<\/p>\n<p><strong>Soluci\u00f3n:<\/strong> Reemplace con cuentas de servicio por etapa usando federaci\u00f3n OIDC. Sin tokens est\u00e1ticos, sin identidades compartidas.<\/p>\n<h3>Deshabilitar la protecci\u00f3n de ramas \u00abtemporalmente\u00bb<\/h3>\n<p>Un despliegue est\u00e1 bloqueado porque una verificaci\u00f3n requerida est\u00e1 fallando. Alguien deshabilita la protecci\u00f3n de ramas para hacer push directamente a main, con la intenci\u00f3n de rehabilitarla despu\u00e9s. Se olvidan, o la rehabilitan pero se pierden una configuraci\u00f3n. Mientras tanto, la ventana sin protecci\u00f3n permiti\u00f3 un push directo que evit\u00f3 la revisi\u00f3n de c\u00f3digo.<\/p>\n<p><strong>Soluci\u00f3n:<\/strong> Nunca deshabilite la protecci\u00f3n de ramas. Si una verificaci\u00f3n requerida est\u00e1 fallando, corrija la verificaci\u00f3n o use un proceso de emergencia que requiera m\u00faltiples aprobaciones y cree un registro de auditor\u00eda.<\/p>\n<h3>Runners compartidos entre producci\u00f3n y cargas de trabajo de PR<\/h3>\n<p>Los pipelines de pull request de forks se ejecutan en la misma infraestructura que tiene acceso de red a sistemas de producci\u00f3n. Un PR malicioso puede exfiltrar secretos, acceder a servicios internos o pivotar a la infraestructura de producci\u00f3n.<\/p>\n<p><strong>Soluci\u00f3n:<\/strong> Use pools de runners separados. Las cargas de trabajo no confiables (PRs, especialmente de forks) se ejecutan en runners ef\u00edmeros y aislados sin acceso a entornos sensibles. Los runners de despliegue a producci\u00f3n est\u00e1n restringidos solo a ramas protegidas.<\/p>\n<h3>Acceso manual por SSH cuando los pipelines fallan<\/h3>\n<p>Cuando un pipeline de despliegue falla, un ingeniero se conecta por SSH directamente a un servidor de producci\u00f3n y despliega manualmente. Esto evita cada control en el pipeline: revisi\u00f3n de c\u00f3digo, pruebas automatizadas, firma de artefactos, aprobaci\u00f3n de despliegue y registro de auditor\u00eda.<\/p>\n<p><strong>Soluci\u00f3n:<\/strong> Invierta en la fiabilidad del pipeline para que la intervenci\u00f3n manual sea raramente necesaria. Cuando sea necesaria, use un procedimiento de emergencia (break-glass) que requiera m\u00faltiples aprobaciones, cree un registro de auditor\u00eda y active una revisi\u00f3n post-incidente.<\/p>\n<h2>Conclusi\u00f3n<\/h2>\n<p>La separaci\u00f3n de responsabilidades y el m\u00ednimo privilegio no son una carga burocr\u00e1tica impuesta por un equipo de cumplimiento. Son controles de ingenier\u00eda que reducen directamente el radio de impacto de los incidentes de seguridad en su pipeline de entrega de software.<\/p>\n<p>Un paso de build comprometido con m\u00ednimo privilegio puede producir un artefacto malicioso \u2014 pero no puede desplegar ese artefacto en producci\u00f3n. Una credencial de despliegue comprometida delimitada a staging no puede alcanzar producci\u00f3n. Un pull request malicioso procesado por un runner aislado no puede exfiltrar secretos de producci\u00f3n. Cada control limita lo que un atacante puede lograr en cada etapa.<\/p>\n<p>Comience auditando los permisos actuales de su pipeline. Identifique cada cuenta de servicio, cada credencial almacenada y cada secreto al que su pipeline puede acceder. Mapee cada uno a la etapa y tarea espec\u00edfica que lo necesita. Luego comience a reducir el alcance: reemplace credenciales est\u00e1ticas con OIDC, divida las cuentas de servicio \u00fanicas en identidades por etapa, agregue puertas de aprobaci\u00f3n para despliegues a producci\u00f3n y proteja las definiciones de su pipeline con CODEOWNERS y protecci\u00f3n de ramas.<\/p>\n<p>No tiene que hacerlo todo de una vez. Cada mejora incremental reduce el riesgo. Pero comience \u2014 porque su pipeline CI\/CD es probablemente el sistema m\u00e1s privilegiado y menos examinado en toda su infraestructura.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introducci\u00f3n La mayor\u00eda de los pipelines CI\/CD comienzan con un objetivo simple: llevar el c\u00f3digo desde la m\u00e1quina de un desarrollador a producci\u00f3n lo m\u00e1s r\u00e1pido posible. En el camino, alguien crea una cuenta de servicio, le otorga permisos amplios, almacena las credenciales como un secreto del pipeline y sigue adelante. Funciona. Los builds pasan, &#8230; <a title=\"Separaci\u00f3n de Responsabilidades y M\u00ednimo Privilegio en Pipelines CI\/CD\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/separation-of-duties-least-privilege-ci-cd-pipelines\/\" aria-label=\"Leer m\u00e1s sobre Separaci\u00f3n de Responsabilidades y M\u00ednimo Privilegio en Pipelines 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-642","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\/642","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=642"}],"version-history":[{"count":1,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/642\/revisions"}],"predecessor-version":[{"id":654,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/642\/revisions\/654"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/media?parent=642"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/categories?post=642"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/tags?post=642"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/post_folder?post=642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}