{"id":644,"date":"2026-01-31T12:15:30","date_gmt":"2026-01-31T11:15:30","guid":{"rendered":"https:\/\/secure-pipelines.com\/?p=644"},"modified":"2026-03-24T18:08:05","modified_gmt":"2026-03-24T17:08:05","slug":"secure-deployment-workflows-ci-cd-pipeline-production","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/secure-deployment-workflows-ci-cd-pipeline-production\/","title":{"rendered":"Workflows de Despliegue Seguros: Del Pipeline CI\/CD a Producci\u00f3n"},"content":{"rendered":"<p>Tu pipeline CI\/CD puede tener controles de seguridad herm\u00e9ticos \u2014commits firmados, dependencias fijadas, escaneos SAST, firma de im\u00e1genes de contenedores\u2014 pero nada de eso importa si el proceso de despliegue en s\u00ed es d\u00e9bil. El despliegue es la uni\u00f3n cr\u00edtica donde la seguridad del pipeline se encuentra con la seguridad en producci\u00f3n. Un workflow de despliegue comprometido puede eludir cada control upstream que hayas construido, empujando c\u00f3digo malicioso directamente al entorno del que dependen tus clientes.<\/p>\n<p>Esta gu\u00eda cubre c\u00f3mo construir workflows de despliegue seguros de extremo a extremo: elegir el modelo de despliegue adecuado, aplicar gates y aprobaciones, verificar artefactos en el momento del despliegue, implementar cambios de forma progresiva y mantener una pista de auditor\u00eda completa desde el commit hasta producci\u00f3n.<\/p>\n<h2 class=\"wp-block-heading\">Modelos de Despliegue: Push-Based vs Pull-Based (GitOps)<\/h2>\n<p>La primera decisi\u00f3n arquitect\u00f3nica que define tu postura de seguridad en el despliegue es si utilizas un modelo push-based o pull-based.<\/p>\n<h3 class=\"wp-block-heading\">Despliegues Push-Based (Impulsados por CI)<\/h3>\n<p>En un modelo push-based tradicional, el pipeline CI\/CD construye el artefacto y luego lo env\u00eda directamente al entorno de destino. GitHub Actions despliega en Kubernetes v\u00eda <code>kubectl apply<\/code>, o un job de GitLab CI ejecuta <code>helm upgrade<\/code> contra un cl\u00faster. El pipeline en s\u00ed posee las credenciales del entorno de producci\u00f3n.<\/p>\n<p>Este modelo es directo pero conlleva un riesgo inherente: el runner de CI tiene acceso de escritura directo a producci\u00f3n. Si un atacante compromete el pipeline \u2014a trav\u00e9s de una dependencia envenenada, un pull request malicioso o un secreto robado\u2014 hereda ese acceso a producci\u00f3n de forma inmediata.<\/p>\n<h3 class=\"wp-block-heading\">Despliegues Pull-Based (GitOps)<\/h3>\n<p>En un modelo pull-based o GitOps, un controlador dedicado que se ejecuta dentro del entorno de destino \u2014como <strong>Flux<\/strong> o <strong>ArgoCD<\/strong>\u2014 observa un repositorio Git en busca de cambios en el estado deseado. Cuando se hace commit de un nuevo manifiesto (t\u00edpicamente el pipeline CI actualizando un tag de imagen), el controlador extrae el cambio y reconcilia el cl\u00faster para que coincida.<\/p>\n<p>La ventaja de seguridad es significativa. El pipeline CI nunca necesita credenciales directas al cl\u00faster de producci\u00f3n. La superficie de ataque se reduce porque el agente de despliegue vive dentro del cl\u00faster y solo extrae de una fuente conocida. La detecci\u00f3n de drift est\u00e1 incorporada: si alguien modifica manualmente un recurso, el controlador lo revierte para que coincida con Git.<\/p>\n<p><strong>Recomendaci\u00f3n:<\/strong> Para cargas de trabajo en producci\u00f3n, prefiere un modelo pull-based de GitOps. Reserva los despliegues push-based para entornos de desarrollo y staging donde la velocidad importa m\u00e1s que el control de acceso estricto. Incluso en configuraciones push-based, aplica el principio de m\u00ednimo privilegio rigurosamente a las credenciales de despliegue.<\/p>\n<h2 class=\"wp-block-heading\">Gates de Despliegue: Aprobaciones Manuales y Entornos Protegidos<\/h2>\n<p>Los pipelines automatizados son r\u00e1pidos, pero el despliegue a producci\u00f3n no deber\u00eda ocurrir sin verificaci\u00f3n humana para cambios de alto impacto. Los gates de despliegue introducen puntos de control que requieren aprobaci\u00f3n expl\u00edcita antes de que un release proceda.<\/p>\n<h3 class=\"wp-block-heading\">GitHub Environments y Revisores Requeridos<\/h3>\n<p>GitHub Actions soporta <strong>Environments<\/strong> con reglas de protecci\u00f3n. Puedes requerir que uno o m\u00e1s revisores aprueben un despliegue antes de que el job se ejecute. Esto se configura en los ajustes del repositorio y se aplica a nivel de plataforma \u2014el c\u00f3digo del pipeline no puede eludirlo.<\/p>\n<pre><code># .github\/workflows\/deploy.yml\njobs:\n  deploy-production:\n    runs-on: ubuntu-latest\n    environment:\n      name: production\n      url: https:\/\/app.example.com\n    steps:\n      - name: Checkout\n        uses: actions\/checkout@v4\n\n      - name: Verify artifact signature\n        run: |\n          cosign verify \\\n            --key cosign.pub \\\n            ghcr.io\/myorg\/myapp:${{ github.sha }}\n\n      - name: Deploy to production\n        run: |\n          helm upgrade --install myapp .\/chart \\\n            --set image.tag=${{ github.sha }} \\\n            --namespace production\n<\/code><\/pre>\n<p>Con el environment <code>production<\/code> configurado para requerir revisores, este job se pausar\u00e1 y esperar\u00e1 aprobaci\u00f3n antes de ejecutar cualquier paso. El aprobador ve exactamente qu\u00e9 commit y ejecuci\u00f3n de workflow desencaden\u00f3 el despliegue.<\/p>\n<h3 class=\"wp-block-heading\">GitLab Protected Environments<\/h3>\n<p>GitLab ofrece <strong>protected environments<\/strong> que restringen qu\u00e9 usuarios o grupos pueden desencadenar despliegues. Combinado con jobs manuales, esto crea un workflow de aprobaci\u00f3n robusto.<\/p>\n<pre><code># .gitlab-ci.yml\ndeploy_production:\n  stage: deploy\n  environment:\n    name: production\n    url: https:\/\/app.example.com\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\"\n      when: manual\n  script:\n    - cosign verify --key cosign.pub $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA\n    - helm upgrade --install myapp .\/chart\n        --set image.tag=$CI_COMMIT_SHA\n        --namespace production\n  resource_group: production\n<\/code><\/pre>\n<p>La directiva <code>when: manual<\/code> requiere que un usuario haga clic en \u00abPlay\u00bb en la interfaz de GitLab. El <code>resource_group<\/code> asegura que solo un despliegue se ejecute a la vez, previniendo condiciones de carrera.<\/p>\n<h3 class=\"wp-block-heading\">Aprobaciones Basadas en Slack y ChatOps<\/h3>\n<p>Para equipos que viven en Slack, integrar workflows de aprobaci\u00f3n con chat proporciona visibilidad y tiempos de respuesta r\u00e1pidos. Herramientas como <strong>Opsgenie<\/strong>, <strong>PagerDuty<\/strong> o bots personalizados de Slack pueden publicar una solicitud de despliegue en un canal y esperar a que un usuario autorizado apruebe mediante un bot\u00f3n o una reacci\u00f3n. El requisito clave es que el mecanismo de aprobaci\u00f3n sea auditable y no pueda ser falsificado \u2014usa tokens verificados de la app de Slack y registra cada decisi\u00f3n de aprobaci\u00f3n.<\/p>\n<h2 class=\"wp-block-heading\">Verificaci\u00f3n de Artefactos en el Momento del Despliegue<\/h2>\n<p>Firmar artefactos durante la fase de build es solo la mitad de la ecuaci\u00f3n. Debes <strong>verificar<\/strong> esas firmas en el momento del despliegue. De lo contrario, un atacante que obtenga acceso a tu registry puede reemplazar una imagen firmada con una maliciosa sin firmar o re-firmada.<\/p>\n<h3 class=\"wp-block-heading\">Verificaci\u00f3n con Cosign Antes del Despliegue<\/h3>\n<p>A\u00f1ade un paso de verificaci\u00f3n expl\u00edcito en tu pipeline de despliegue que se ejecute antes de cualquier comando de despliegue. Si la verificaci\u00f3n falla, el pipeline debe detenerse de inmediato.<\/p>\n<pre><code># Verificar la firma de la imagen antes de desplegar\ncosign verify \\\n  --certificate-identity \"https:\/\/github.com\/myorg\/myapp\/.github\/workflows\/build.yml@refs\/heads\/main\" \\\n  --certificate-oidc-issuer \"https:\/\/token.actions.githubusercontent.com\" \\\n  ghcr.io\/myorg\/myapp@sha256:abc123...\n\n# Verificar la procedencia SLSA\ncosign verify-attestation \\\n  --type slsaprovenance \\\n  --certificate-identity \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/.github\/workflows\/generator_container_slsa3.yml@refs\/tags\/v1.9.0\" \\\n  --certificate-oidc-issuer \"https:\/\/token.actions.githubusercontent.com\" \\\n  ghcr.io\/myorg\/myapp@sha256:abc123...\n<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Admission Controllers: Kyverno y Sigstore Policy Controller<\/h3>\n<p>La verificaci\u00f3n a nivel de pipeline es buena, pero puede ser eludida si alguien despliega directamente al cl\u00faster usando <code>kubectl<\/code>. Los <strong>admission controllers<\/strong> aplican la verificaci\u00f3n a nivel del API server de Kubernetes \u2014ninguna imagen sin firmar puede entrar al cl\u00faster independientemente de c\u00f3mo fue enviada.<\/p>\n<p><strong>Kyverno<\/strong> es un motor de pol\u00edticas nativo de Kubernetes que puede verificar firmas de im\u00e1genes y attestations como parte de su admission webhook:<\/p>\n<pre><code>apiVersion: kyverno.io\/v1\nkind: ClusterPolicy\nmetadata:\n  name: require-signed-images\nspec:\n  validationFailureAction: Enforce\n  background: false\n  rules:\n    - name: verify-signature\n      match:\n        any:\n          - resources:\n              kinds:\n                - Pod\n      verifyImages:\n        - imageReferences:\n            - \"ghcr.io\/myorg\/*\"\n          attestors:\n            - entries:\n                - keyless:\n                    subject: \"https:\/\/github.com\/myorg\/*\"\n                    issuer: \"https:\/\/token.actions.githubusercontent.com\"\n          attestations:\n            - type: https:\/\/slsa.dev\/provenance\/v1\n              conditions:\n                - all:\n                    - key: \"{{ builder.id }}\"\n                      operator: Equals\n                      value: \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/.github\/workflows\/generator_container_slsa3.yml@refs\/tags\/v1.9.0\"\n<\/code><\/pre>\n<p>El <strong>Sigstore Policy Controller<\/strong> (anteriormente cosigned) proporciona funcionalidad similar y es mantenido por el proyecto Sigstore. Se integra estrechamente con los workflows de firma keyless y es una excelente opci\u00f3n si tu organizaci\u00f3n se ha estandarizado en el ecosistema Sigstore.<\/p>\n<p>La combinaci\u00f3n de verificaci\u00f3n a nivel de pipeline y control de admisi\u00f3n a nivel de cl\u00faster crea defensa en profundidad: incluso si una capa es eludida, la otra detecta artefactos no autorizados.<\/p>\n<h2 class=\"wp-block-heading\">Rollouts Progresivos: Canary, Blue-Green y Feature Flags<\/h2>\n<p>Desplegar una nueva versi\u00f3n al 100% del tr\u00e1fico de forma instant\u00e1nea es un riesgo de seguridad y confiabilidad. Las estrategias de rollout progresivo te permiten detectar problemas \u2014incluyendo problemas de seguridad\u2014 antes de que afecten a todos los usuarios.<\/p>\n<h3 class=\"wp-block-heading\">Despliegues Canary<\/h3>\n<p>Un despliegue canary enruta un peque\u00f1o porcentaje del tr\u00e1fico (por ejemplo, 5%) a la nueva versi\u00f3n mientras la mayor\u00eda contin\u00faa llegando al release estable. Si m\u00e9tricas como tasas de error, latencia o se\u00f1ales de seguridad (conexiones salientes inesperadas, escalaciones de privilegios elevadas) se degradan, el canary se revierte autom\u00e1ticamente.<\/p>\n<p>Herramientas como <strong>Flagger<\/strong> (para Kubernetes), <strong>AWS App Mesh<\/strong> e <strong>Istio<\/strong> automatizan el an\u00e1lisis canary. Flagger, por ejemplo, puede configurarse para monitorear m\u00e9tricas personalizadas de Prometheus y promover o revertir autom\u00e1ticamente:<\/p>\n<pre><code>apiVersion: flagger.app\/v1beta1\nkind: Canary\nmetadata:\n  name: myapp\n  namespace: production\nspec:\n  targetRef:\n    apiVersion: apps\/v1\n    kind: Deployment\n    name: myapp\n  progressDeadlineSeconds: 600\n  service:\n    port: 8080\n  analysis:\n    interval: 1m\n    threshold: 5\n    maxWeight: 50\n    stepWeight: 10\n    metrics:\n      - name: request-success-rate\n        thresholdRange:\n          min: 99\n        interval: 1m\n      - name: request-duration\n        thresholdRange:\n          max: 500\n        interval: 1m\n<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Despliegues Blue-Green<\/h3>\n<p>Los despliegues blue-green mantienen dos entornos id\u00e9nticos. El entorno \u00abblue\u00bb ejecuta la versi\u00f3n actual; el \u00abgreen\u00bb ejecuta la nueva. El tr\u00e1fico se cambia de una vez (t\u00edpicamente v\u00eda un load balancer o cambio de DNS) despu\u00e9s de que el entorno green pasa las verificaciones de salud y la validaci\u00f3n de seguridad. Si algo sale mal, el cambio de vuelta a blue es instant\u00e1neo.<\/p>\n<p>El beneficio de seguridad es una ruta de rollback limpia y predecible. No hay estado parcial que analizar, y la versi\u00f3n anterior permanece completamente operativa durante todo el despliegue.<\/p>\n<h3 class=\"wp-block-heading\">Feature Flags como Controles de Seguridad<\/h3>\n<p>Los feature flags desacoplan el despliegue del release. El c\u00f3digo se despliega en producci\u00f3n pero permanece inactivo detr\u00e1s de un flag. Esto le da a los equipos de seguridad un kill switch: si una funcionalidad reci\u00e9n lanzada introduce una vulnerabilidad o se comporta de forma inesperada, puede desactivarse instant\u00e1neamente sin un rollback completo. Herramientas como <strong>LaunchDarkly<\/strong>, <strong>Unleash<\/strong> y <strong>OpenFeature<\/strong> proporcionan gesti\u00f3n centralizada de flags con logs de auditor\u00eda de qui\u00e9n activ\u00f3 qu\u00e9 y cu\u00e1ndo.<\/p>\n<h2 class=\"wp-block-heading\">Estrategias de Rollback<\/h2>\n<p>Cada plan de despliegue debe incluir un plan de rollback. Cuando las cosas salen mal \u2014y saldr\u00e1n\u2014 la velocidad y confiabilidad de tu rollback determina directamente el radio de impacto.<\/p>\n<h3 class=\"wp-block-heading\">Rollback Autom\u00e1tico por Fallo en Health Check<\/h3>\n<p>Kubernetes soporta nativamente el rollback a trav\u00e9s de su deployment controller. Si los nuevos pods fallan en las pruebas de readiness o liveness, el rollout se detiene y puede revertirse autom\u00e1ticamente:<\/p>\n<pre><code># Verificar el estado del rollout y hacer rollback si es necesario\nkubectl rollout status deployment\/myapp --namespace production --timeout=300s\nif [ $? -ne 0 ]; then\n  echo \"Rollout fall\u00f3, iniciando rollback\"\n  kubectl rollout undo deployment\/myapp --namespace production\n  exit 1\nfi\n<\/code><\/pre>\n<p>En un modelo GitOps, el rollback significa revertir el commit de Git que introdujo el cambio. El controlador detecta la reversi\u00f3n y reconcilia el cl\u00faster de vuelta al estado anterior. Esto preserva la pista de auditor\u00eda completa en Git.<\/p>\n<h3 class=\"wp-block-heading\">Despliegues Inmutables<\/h3>\n<p>Los despliegues inmutables tratan cada release como una instancia nueva y desechable. En lugar de actualizar contenedores en su lugar, despliegas un conjunto completamente nuevo de recursos y decomisionas los antiguos. Esto elimina el drift de configuraci\u00f3n y asegura que lo que se prob\u00f3 es exactamente lo que se ejecuta en producci\u00f3n. Combinado con digests de imagen (en lugar de tags mutables como <code>latest<\/code>), los despliegues inmutables garantizan reproducibilidad binaria.<\/p>\n<h2 class=\"wp-block-heading\">Separaci\u00f3n de Identidades de Build y Deploy<\/h2>\n<p>Una de las mejoras de seguridad m\u00e1s impactantes que puedes realizar es asegurar que la identidad utilizada para construir artefactos sea diferente de la identidad utilizada para desplegarlos. Esto limita el radio de impacto de un compromiso en cualquiera de las fases.<\/p>\n<h3 class=\"wp-block-heading\">Credenciales Diferentes<\/h3>\n<p>El pipeline de build deber\u00eda tener credenciales para enviar im\u00e1genes a un registry y firmarlas \u2014pero sin acceso a la infraestructura de producci\u00f3n. El pipeline de despliegue (o el controlador GitOps) deber\u00eda tener credenciales para extraer im\u00e1genes y aplicar manifiestos \u2014pero sin acceso a los repositorios de c\u00f3digo fuente ni a las claves de firma.<\/p>\n<p>En la pr\u00e1ctica, esto significa utilizar service accounts, roles IAM o claims OIDC separados para cada fase. En AWS, el rol de build podr\u00eda tener permisos para ECR push y firma KMS, mientras que el rol de deploy tiene permisos para EKS y Secrets Manager pero no para ECR push.<\/p>\n<h3 class=\"wp-block-heading\">Runners Diferentes<\/h3>\n<p>Lleva la separaci\u00f3n m\u00e1s lejos ejecutando los jobs de build y deploy en runners f\u00edsicamente diferentes. Los jobs de build se ejecutan en runners ef\u00edmeros de prop\u00f3sito general. Los jobs de deploy se ejecutan en runners dedicados y reforzados que se encuentran dentro de un per\u00edmetro de red m\u00e1s cercano al entorno de producci\u00f3n. Esto previene que un runner de build comprometido pivote hacia producci\u00f3n.<\/p>\n<p>Para un tratamiento m\u00e1s profundo de la separaci\u00f3n de identidades y los principios de m\u00ednimo privilegio en CI\/CD, consulta nuestra gu\u00eda sobre <a href=\"https:\/\/secure-pipelines.com\/es\/?p=642\">Separaci\u00f3n de Responsabilidades y M\u00ednimo Privilegio en Pipelines CI\/CD<\/a>.<\/p>\n<h2 class=\"wp-block-heading\">Congelaci\u00f3n de Despliegues y Ventanas de Cambio<\/h2>\n<p>No todo momento es bueno para desplegar. Las congelaciones de despliegue \u2014per\u00edodos durante los cuales los cambios en producci\u00f3n est\u00e1n prohibidos\u2014 reducen el riesgo durante eventos de alto tr\u00e1fico, vacaciones, transiciones de guardia o respuesta activa a incidentes.<\/p>\n<p>Implementa las congelaciones a nivel de plataforma, no solo como un acuerdo de equipo. GitHub Environments soporta <strong>deployment branch policies<\/strong> y <strong>wait timers<\/strong>. GitLab permite <strong>deploy freezes<\/strong> configurados v\u00eda la interfaz o API con programaciones estilo cron. Para workflows basados en Kubernetes, puedes aplicar congelaciones con una pol\u00edtica de OPA\/Gatekeeper o Kyverno que rechace despliegues durante ventanas de tiempo espec\u00edficas.<\/p>\n<pre><code># Pol\u00edtica Kyverno para aplicar congelaci\u00f3n de despliegue\napiVersion: kyverno.io\/v1\nkind: ClusterPolicy\nmetadata:\n  name: deployment-freeze\nspec:\n  validationFailureAction: Enforce\n  background: false\n  rules:\n    - name: block-deployments-during-freeze\n      match:\n        any:\n          - resources:\n              kinds:\n                - Deployment\n              namespaces:\n                - production\n      preconditions:\n        all:\n          - key: \"{{ time_now() }}\"\n            operator: GreaterThan\n            value: \"2026-03-27T00:00:00Z\"  # Inicio de congelaci\u00f3n\n          - key: \"{{ time_now() }}\"\n            operator: LessThan\n            value: \"2026-03-30T00:00:00Z\"  # Fin de congelaci\u00f3n\n      validate:\n        message: \"Los despliegues en producci\u00f3n est\u00e1n congelados hasta el 30 de marzo. Contacta a platform-team para excepciones de emergencia.\"\n        deny: {}\n<\/code><\/pre>\n<p>Documenta un proceso de excepci\u00f3n para parches de seguridad de emergencia que necesiten desplegarse durante una congelaci\u00f3n, incluyendo qui\u00e9n puede autorizar la excepci\u00f3n y c\u00f3mo se registra.<\/p>\n<h2 class=\"wp-block-heading\">Pista de Auditor\u00eda: Vinculando Despliegues con Commits, Aprobadores y Ejecuciones de Pipeline<\/h2>\n<p>Un workflow de despliegue seguro produce una pista de auditor\u00eda completa y a prueba de manipulaciones. Para cada despliegue en producci\u00f3n, deber\u00edas poder responder: <em>\u00bfQu\u00e9<\/em> se despleg\u00f3? <em>\u00bfQui\u00e9n<\/em> lo aprob\u00f3? <em>\u00bfQu\u00e9<\/em> pipeline lo construy\u00f3? <em>\u00bfA qu\u00e9<\/em> commit se remonta?<\/p>\n<h3 class=\"wp-block-heading\">Logs de Auditor\u00eda a Nivel de Plataforma<\/h3>\n<p><strong>AWS CloudTrail<\/strong> registra las llamadas API a EKS, ECS y Lambda, incluyendo qui\u00e9n inici\u00f3 el despliegue y desde qu\u00e9 fuente. <strong>GCP Audit Logs<\/strong> proporcionan cobertura similar para GKE y Cloud Run. Aseg\u00farate de que estos logs se env\u00eden a un almac\u00e9n de logs centralizado e inmutable (como un bucket S3 dedicado con object lock o un SIEM) donde no puedan ser manipulados por un atacante que haya comprometido el entorno de despliegue.<\/p>\n<h3 class=\"wp-block-heading\">Trazabilidad a Nivel de Pipeline<\/h3>\n<p>Anota los recursos de Kubernetes con metadatos de despliegue para que puedas rastrear desde un pod en ejecuci\u00f3n hasta la fuente exacta:<\/p>\n<pre><code># Incluir en tu Helm chart o Kustomize overlay\nmetadata:\n  labels:\n    app.kubernetes.io\/version: \"{{ .Values.image.tag }}\"\n  annotations:\n    deploy.example.com\/commit-sha: \"{{ .Values.commitSha }}\"\n    deploy.example.com\/pipeline-url: \"{{ .Values.pipelineUrl }}\"\n    deploy.example.com\/approved-by: \"{{ .Values.approvedBy }}\"\n    deploy.example.com\/deployed-at: \"{{ now | date \\\"2006-01-02T15:04:05Z\\\" }}\"\n<\/code><\/pre>\n<p>En GitHub Actions, pasa estos valores a trav\u00e9s del workflow de despliegue:<\/p>\n<pre><code>- name: Deploy with traceability\n  run: |\n    helm upgrade --install myapp .\/chart \\\n      --set image.tag=${{ github.sha }} \\\n      --set commitSha=${{ github.sha }} \\\n      --set pipelineUrl=\"https:\/\/github.com\/${{ github.repository }}\/actions\/runs\/${{ github.run_id }}\" \\\n      --set approvedBy=\"${{ github.actor }}\" \\\n      --namespace production\n<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Monitoreo Post-Despliegue<\/h2>\n<p>El despliegue no termina cuando la nueva versi\u00f3n est\u00e1 en ejecuci\u00f3n. El monitoreo post-despliegue cierra el ciclo de retroalimentaci\u00f3n y detecta problemas que las verificaciones pre-despliegue no detectaron.<\/p>\n<h3 class=\"wp-block-heading\">Detecci\u00f3n de Anomal\u00edas<\/h3>\n<p>Establece m\u00e9tricas de referencia para el comportamiento normal de la aplicaci\u00f3n: tasas de solicitudes, tasas de error, percentiles de latencia, uso de CPU\/memoria y patrones de conexi\u00f3n de red. Despu\u00e9s de cada despliegue, compara las m\u00e9tricas actuales contra la referencia. Herramientas como <strong>Prometheus + Alertmanager<\/strong>, <strong>Datadog<\/strong> y <strong>Grafana Alerting<\/strong> pueden activar alertas cuando las m\u00e9tricas post-despliegue se desv\u00edan m\u00e1s all\u00e1 de los umbrales.<\/p>\n<p>Desde una perspectiva de seguridad, presta especial atenci\u00f3n a conexiones de red salientes inesperadas, nuevos procesos generados dentro de contenedores, llamadas al sistema elevadas y aumentos repentinos en fallos de autenticaci\u00f3n. Estos pueden indicar que un artefacto comprometido pas\u00f3 a trav\u00e9s del pipeline.<\/p>\n<h3 class=\"wp-block-heading\">M\u00e9tricas DORA para Seguridad<\/h3>\n<p>Las cuatro m\u00e9tricas DORA \u2014frecuencia de despliegue, lead time para cambios, tasa de fallo de cambios y tiempo medio de recuperaci\u00f3n\u2014 se utilizan t\u00edpicamente para medir el rendimiento de DevOps. Son igualmente valiosas para la seguridad:<\/p>\n<ul class=\"wp-block-list\">\n<li><strong>Frecuencia de despliegue<\/strong> indica con qu\u00e9 frecuencia puedes enviar parches de seguridad. Mayor frecuencia significa remediaci\u00f3n m\u00e1s r\u00e1pida.<\/li>\n<li><strong>Lead time para cambios<\/strong> mide qu\u00e9 tan r\u00e1pido un fix de seguridad va desde el commit hasta producci\u00f3n. Lead times largos significan ventanas de exposici\u00f3n extendidas.<\/li>\n<li><strong>Tasa de fallo de cambios<\/strong> rastrea con qu\u00e9 frecuencia los despliegues causan incidentes. Una tasa alta sugiere pruebas o verificaci\u00f3n inadecuadas \u2014una preocupaci\u00f3n de seguridad.<\/li>\n<li><strong>Tiempo medio de recuperaci\u00f3n (MTTR)<\/strong> mide qu\u00e9 tan r\u00e1pido puedes hacer rollback o remediar un despliegue fallido. Un MTTR bajo limita el radio de impacto de cualquier incidente, incluyendo una brecha de seguridad.<\/li>\n<\/ul>\n<p>Rastrea estas m\u00e9tricas por entorno y correl\u00e1cionolas con eventos de seguridad. Si tu tasa de fallo de cambios se dispara despu\u00e9s de adoptar un nuevo patr\u00f3n de despliegue, investiga antes de que se convierta en un problema de seguridad.<\/p>\n<h2 class=\"wp-block-heading\">Integrando Todo: Un Pipeline de Despliegue Seguro Completo<\/h2>\n<p>Aqu\u00ed hay un workflow completo de GitHub Actions que incorpora las pr\u00e1cticas discutidas anteriormente \u2014verificaci\u00f3n de artefactos, aprobaciones basadas en environments, trazabilidad de despliegue y rollback autom\u00e1tico:<\/p>\n<pre><code># .github\/workflows\/secure-deploy.yml\nname: Secure Deployment\n\non:\n  workflow_run:\n    workflows: [\"Build and Sign\"]\n    types: [completed]\n    branches: [main]\n\njobs:\n  verify-and-deploy:\n    runs-on: ubuntu-latest\n    if: ${{ github.event.workflow_run.conclusion == 'success' }}\n    environment:\n      name: production\n      url: https:\/\/app.example.com\n    permissions:\n      id-token: write\n      contents: read\n    steps:\n      - name: Checkout manifests\n        uses: actions\/checkout@v4\n\n      - name: Install cosign\n        uses: sigstore\/cosign-installer@v3\n\n      - name: Verify image signature (keyless)\n        run: |\n          IMAGE=\"ghcr.io\/myorg\/myapp@${{ github.event.workflow_run.head_sha }}\"\n          cosign verify \\\n            --certificate-identity \"https:\/\/github.com\/myorg\/myapp\/.github\/workflows\/build.yml@refs\/heads\/main\" \\\n            --certificate-oidc-issuer \"https:\/\/token.actions.githubusercontent.com\" \\\n            \"$IMAGE\"\n\n      - name: Verify SLSA provenance\n        run: |\n          IMAGE=\"ghcr.io\/myorg\/myapp@${{ github.event.workflow_run.head_sha }}\"\n          cosign verify-attestation \\\n            --type slsaprovenance \\\n            --certificate-identity \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/.github\/workflows\/generator_container_slsa3.yml@refs\/tags\/v1.9.0\" \\\n            --certificate-oidc-issuer \"https:\/\/token.actions.githubusercontent.com\" \\\n            \"$IMAGE\"\n\n      - name: Configure AWS credentials (deploy role)\n        uses: aws-actions\/configure-aws-credentials@v4\n        with:\n          role-to-assume: arn:aws:iam::123456789012:role\/deploy-production\n          aws-region: us-east-1\n\n      - name: Deploy to EKS\n        run: |\n          aws eks update-kubeconfig --name production-cluster\n          helm upgrade --install myapp .\/chart \\\n            --set image.tag=${{ github.event.workflow_run.head_sha }} \\\n            --set commitSha=${{ github.event.workflow_run.head_sha }} \\\n            --set pipelineUrl=\"https:\/\/github.com\/${{ github.repository }}\/actions\/runs\/${{ github.run_id }}\" \\\n            --set approvedBy=\"${{ github.actor }}\" \\\n            --namespace production \\\n            --wait --timeout 300s\n\n      - name: Verify rollout\n        run: |\n          kubectl rollout status deployment\/myapp \\\n            --namespace production --timeout=300s\n\n      - name: Rollback on failure\n        if: failure()\n        run: |\n          echo \"Despliegue fallido \u2014 iniciando rollback\"\n          kubectl rollout undo deployment\/myapp --namespace production\n          echo \"::error::Despliegue revertido debido a fallo\"\n<\/code><\/pre>\n<p>Y el pipeline equivalente de GitLab CI con controles similares:<\/p>\n<pre><code># .gitlab-ci.yml\nstages:\n  - verify\n  - deploy\n  - validate\n\nverify_artifact:\n  stage: verify\n  image: bitnami\/cosign:latest\n  script:\n    - cosign verify\n        --certificate-identity \"https:\/\/gitlab.com\/myorg\/myapp\/\/.gitlab-ci.yml@refs\/heads\/main\"\n        --certificate-oidc-issuer \"https:\/\/gitlab.com\"\n        $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\"\n\ndeploy_production:\n  stage: deploy\n  environment:\n    name: production\n    url: https:\/\/app.example.com\n  resource_group: production\n  needs: [verify_artifact]\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\"\n      when: manual\n  script:\n    - aws eks update-kubeconfig --name production-cluster\n    - helm upgrade --install myapp .\/chart\n        --set image.tag=$CI_COMMIT_SHA\n        --set commitSha=$CI_COMMIT_SHA\n        --set pipelineUrl=$CI_PIPELINE_URL\n        --set approvedBy=$GITLAB_USER_LOGIN\n        --namespace production\n        --wait --timeout 300s\n\nvalidate_deployment:\n  stage: validate\n  needs: [deploy_production]\n  script:\n    - kubectl rollout status deployment\/myapp --namespace production --timeout=300s\n  after_script:\n    - |\n      if [ \"$CI_JOB_STATUS\" == \"failed\" ]; then\n        echo \"Revirtiendo despliegue\"\n        kubectl rollout undo deployment\/myapp --namespace production\n      fi\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\"\n<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Resumen y Gu\u00edas Relacionadas<\/h2>\n<p>Los workflows de despliegue seguros requieren defensa en profundidad en cada fase: elegir el modelo de despliegue correcto, aplicar gates y aprobaciones, verificar artefactos en el l\u00edmite del cl\u00faster, implementar cambios de forma progresiva, mantener rutas de rollback limpias, separar las identidades de build y deploy, respetar las ventanas de cambio y registrar todo. Ning\u00fan control individual es suficiente por s\u00ed solo. La combinaci\u00f3n de verificaci\u00f3n a nivel de pipeline, aplicaci\u00f3n de admission controllers, rollouts progresivos y logging de auditor\u00eda integral crea un proceso de despliegue que es r\u00e1pido y seguro a la vez.<\/p>\n<p>Contin\u00faa desarrollando tu conocimiento de CI\/CD seguro con estas gu\u00edas relacionadas:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/secure-pipelines.com\/es\/?p=642\">Separaci\u00f3n de Responsabilidades y M\u00ednimo Privilegio en Pipelines CI\/CD<\/a> \u2014 Profundizaci\u00f3n en la separaci\u00f3n de identidades, credenciales con alcance limitado y el principio de m\u00ednimo privilegio a lo largo de tu pipeline.<\/li>\n<li><a href=\"https:\/\/secure-pipelines.com\/es\/?p=647\">Patrones Defensivos y Mitigaciones para Ataques a Pipelines CI\/CD<\/a> \u2014 Contramedidas pr\u00e1cticas para los vectores de ataque m\u00e1s comunes que apuntan a sistemas CI\/CD.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Tu pipeline CI\/CD puede tener controles de seguridad herm\u00e9ticos \u2014commits firmados, dependencias fijadas, escaneos SAST, firma de im\u00e1genes de contenedores\u2014 pero nada de eso importa si el proceso de despliegue en s\u00ed es d\u00e9bil. El despliegue es la uni\u00f3n cr\u00edtica donde la seguridad del pipeline se encuentra con la seguridad en producci\u00f3n. Un workflow de &#8230; <a title=\"Workflows de Despliegue Seguros: Del Pipeline CI\/CD a Producci\u00f3n\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/secure-deployment-workflows-ci-cd-pipeline-production\/\" aria-label=\"Leer m\u00e1s sobre Workflows de Despliegue Seguros: Del Pipeline CI\/CD a Producci\u00f3n\">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-644","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\/644","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=644"}],"version-history":[{"count":2,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/644\/revisions"}],"predecessor-version":[{"id":683,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/644\/revisions\/683"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/media?parent=644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/categories?post=644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/tags?post=644"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/post_folder?post=644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}