Módulo 7: Gitops Beyond Terraform

4. *Push-based* vs. *pull-based*: dos GitOps, un principio

Descripción

El Módulo 1, lección 4, dejó una frase pendiente, a propósito: "Aquí, un pipeline de CI (GitHub Actions) empuja el cambio hacia afuera cuando detecta un push a main — esto se llama push-based. En el modelo de Kubernetes con ArgoCD o Flux, un operador que corre dentro del clúster observa el repositorio Git constantemente y jala los cambios hacia adentro cuando los detecta — esto se llama pull-based." Ya construiste el mecanismo push completo (Módulos 3 y 5) y ya conociste, con nombre y forma exacta, el mecanismo pull (lección anterior). Esta lección cierra ese hilo: te muestra, con un diagrama y una tabla de implicaciones concretas —incluida la de seguridad, la más importante de las dos—, por qué son dos mecanismos genuinamente distintos que cumplen el mismo principio de GitOps.

Conexión con el módulo

Esta lección depende directamente de la anterior: sin conocer la forma real de ArgoCD/Flux (lección 3), la distinción push vs. pull sería abstracta. Con esa forma ya conocida, esta lección puede ser concreta y comparar, línea por línea, tu propio apply.yml (Módulo 5) contra el syncPolicy.automated de un Application de ArgoCD. Es la lección más "conceptual pura" de las dos que retoman el Módulo 1 —la lección 2 retomó la evidencia de mercado, esta retoma la distinción técnica— y cierra, con esto, el último hilo abierto de toda la guía. La lección 5 pasa a un territorio nuevo: qué pasa después de que el estado deseado ya está en el clúster (estrategias de despliegue), un problema que ni push ni pull resuelven por sí solos.


Analogía: la carta en la puerta contra el viaje al buzón

Imagina dos formas de recibir correo. En la primera, un cartero camina hasta tu puerta todos los días y entrega la correspondencia directamente en tu buzón de entrada — tú no haces nada, el correo llega solo, empujado desde afuera hacia adentro de tu casa. En la segunda, no hay cartero que toque tu puerta: existe un buzón compartido en la esquina, y eres tú quien camina hasta ahí, revisa si hay algo nuevo, y si lo hay, lo trae hacia adentro. En ambos casos termina la misma carta en tus manos —el resultado final es idéntico—, pero la dirección del movimiento es opuesta: en la primera, alguien de afuera empuja hacia tu casa; en la segunda, tú —desde adentro— vas a buscar hacia afuera.

Esa es, con precisión, la diferencia entre push-based GitOps (la primera: apply.yml empuja el cambio hacia AWS cuando detecta un push a main) y pull-based GitOps (la segunda: ArgoCD, corriendo dentro del clúster, va a buscar el cambio al repositorio de Git cada cierto intervalo). El destino final —infraestructura o clúster actualizados según lo que dice Git— es el mismo en los dos casos. Lo que cambia es quién inicia el movimiento, y como vas a ver más abajo, esa diferencia no es solo semántica: tiene una consecuencia de seguridad real y medible.


El mecanismo, lado a lado

   PUSH-BASED GITOPS (esta guía, Módulos 3 y 5)

   Desarrollador          GitHub                  Pipeline CI          AWS
        │                    │                         │                │
        │──git push─────────▶│                         │                │
        │                    │──dispara apply.yml─────▶│                │
        │                    │                         │──terraform apply──▶│
        │                    │                         │   (CREDENCIALES    │
        │                    │                         │    salen HACIA     │
        │                    │                         │    afuera)         │
        │                    │                         │◀───confirmación────│
        │                    │◀────estado actualizado──│                │

   El PIPELINE inicia el movimiento. Un evento (push a main) lo dispara.
   El pipeline necesita credenciales para escribir en AWS — las credenciales
   viajan HACIA AFUERA del repositorio, hacia el proveedor de nube.


   PULL-BASED GITOPS (ArgoCD/Flux, Kubernetes — nombrado, no construido aquí)

   Desarrollador          GitHub                  ArgoCD/Flux           Clúster K8s
        │                    │                    (corre DENTRO           │
        │                    │                     del clúster)           │
        │──git push─────────▶│                         │                  │
        │                    │◀──── watch/poll cada N minutos ────────────│
        │                    │      (el operador VIENE a buscar,          │
        │                    │       nadie lo empuja)                     │
        │                    │────repositorio actual─▶│                  │
        │                    │                         │──aplica dentro──▶│
        │                    │                         │   del MISMO       │
        │                    │                         │   clúster donde   │
        │                    │                         │   ya corre        │

   El OPERADOR inicia el movimiento. Un temporizador (interval) lo dispara,
   no un evento externo. El operador ya vive dentro del clúster que va a
   modificar — no necesita credenciales que viajen hacia afuera de ningún lado.

La diferencia central, en una frase: en push, algo externo al destino (un pipeline de CI, corriendo en un runner que no es parte de tu infraestructura de AWS) inicia el cambio y necesita permiso para entrar. En pull, algo que ya vive dentro del destino (un controlador corriendo como Pods en el mismo clúster que administra) inicia el cambio por su cuenta, sin que nadie externo lo dispare.


La secuencia completa, en un diagrama de flujo

sequenceDiagram
    participant Dev as Desarrollador
    participant Git as Repositorio Git
    participant CI as Pipeline CI (push)
    participant AWS as AWS (destino, push)
    participant Op as Operador GitOps (pull)
    participant K8s as Clúster K8s (destino, pull)

    Dev->>Git: git push (cambio aprobado)

    rect rgb(235, 245, 255)
    Note over Git,AWS: Mecanismo PUSH — esta guía
    Git-->>CI: evento push dispara apply.yml
    CI->>AWS: terraform apply (credenciales salen hacia AWS)
    AWS-->>CI: infraestructura actualizada
    end

    rect rgb(255, 245, 235)
    Note over Op,K8s: Mecanismo PULL — ArgoCD/Flux
    Op->>Git: poll cada N minutos (el operador pregunta)
    Git-->>Op: último estado del repositorio
    Op->>K8s: aplica el estado (ya vive adentro, sin credenciales externas)
    K8s-->>Op: estado reconciliado
    end

Fíjate en el detalle temporal: en push, el cambio se aplica casi inmediatamente después del push a main — es reactivo, disparado por el evento. En pull, el cambio se aplica en algún momento dentro del próximo intervalo (los 5m0s del GitRepository de Flux que viste en la lección anterior, por ejemplo) — es periódico, no instantáneo. Esta diferencia de latencia es real y a veces importa: un pipeline push puede desplegar en segundos; un operador pull típico tarda, en el peor caso, hasta un intervalo completo — aunque tanto ArgoCD como Flux también soportan disparar una sincronización inmediata vía webhook, para reducir esa latencia cuando hace falta.


La implicación de seguridad, la diferencia que más importa

Esta es la razón técnica por la que la industria de Kubernetes, en particular, prefiere pull sobre push para sus propios despliegues — no es una preferencia estética, es una superficie de ataque distinta:

Push-based (esta guía)Pull-based (ArgoCD/Flux)
¿Quién tiene credenciales de escritura hacia el destino?El pipeline de CI (un sistema externo a AWS)Nadie externo — el operador ya vive dentro del clúster que administra
¿Dónde viven esas credenciales?Como secreto de GitHub Actions (Módulo 4), inyectado en cada corridaNo existen credenciales "externas" — el operador usa el ServiceAccount con el que ya corre dentro del clúster
Si el pipeline de CI se comprometeUn atacante con acceso al pipeline puede usar esas credenciales para escribir en AWS directamenteNo aplica — no hay credenciales de escritura hacia afuera que robar en ese pipeline
Superficie de ataqueEl repositorio Git y el sistema de CI y el canal de credenciales entre ambosSolo el repositorio Git — el operador nunca expone credenciales de escritura fuera del clúster

Esto no significa que push sea "inseguro" — tú mismo construiste, en el Módulo 4, todo el modelo de OIDC (nombrado) que resuelve exactamente este problema: credenciales de corta duración, sin secretos de larga vida almacenados, federadas justo en el momento en que el pipeline las necesita. Significa que pull elimina una categoría entera de riesgo por diseño —nunca hay credenciales de escritura hacia el clúster viajando fuera de él—, mientras que push la gestiona con buenas prácticas (OIDC, secretos rotables, permisos mínimos) en vez de eliminarla de raíz. Es la razón técnica real, no una moda, detrás de por qué Kubernetes en producción tiende hacia pull, y por qué esta distinción vale la pena que la tengas clara si alguna vez tienes que justificar, en un diseño real, por qué elegiste uno u otro mecanismo.


Las cuatro propiedades de GitOps, confirmadas en ambos mecanismos

Vuelve a las cuatro propiedades del Módulo 1, lección 4 — declarativo, Git como fuente de verdad, aplicación automática, reconciliación continua. Ninguna de las dos, push ni pull, gana o pierde puntos en esa lista: las cuatro se cumplen en ambos casos, solo cambia cómo.

PropiedadCómo la cumple push (esta guía)Cómo la cumple pull (ArgoCD/Flux)
Estado deseado, declaradoHCL de TerraformManifiestos de Kubernetes (YAML de Deployment, etc.)
Git como única fuente de verdadPR revisado antes de fusionar a mainIgual — PR revisado antes de fusionar
Aplicación automática de cambios aprobadosapply.yml, disparado por push a mainEl operador, disparado por su propio interval
Reconciliación continuadrift.yml, programado, detecta y avisaselfHeal: true, continuo, detecta y corrige

La última fila es la diferencia más concreta que ya viste en la lección anterior: ambos mecanismos reconcilian, pero pull típicamente lo hace de forma más agresiva (corrección automática) porque el operador está diseñado para correr indefinidamente, comparando estado sin parar — mientras que drift.yml, un job programado dentro de un sistema de CI pensado para corridas puntuales, es más natural que se detenga en "avisar" y deje la corrección para un apply revisado como cualquier otro cambio.


Errores comunes

Pensar que "pull es mejor que push, siempre" (de generalización apresurada). Qué pasa: alguien, después de leer la sección de seguridad de esta lección, concluye que push es una elección inferior y que esta guía debería haber usado pull desde el principio. Por qué pasa: la tabla de seguridad de arriba muestra una ventaja real de pull, y es fácil generalizar "menos superficie de ataque" a "siempre mejor". Cómo detectarlo: si tu conclusión es que el diseño de esta guía "debería cambiar" a pull. Cómo corregirlo: pull resuelve un problema (superficie de ataque de credenciales) a costa de requerir un clúster de Kubernetes corriendo, con un operador dedicado, con su propio mantenimiento — no es una opción disponible para infraestructura que no es Kubernetes, como el S3, DynamoDB, IAM y Lambda que administra andes-cargo-infra/. No hay un "ArgoCD para Terraform contra AWS puro" ampliamente adoptado equivalente — push sigue siendo, hoy, el mecanismo estándar de la industria para IaC fuera de Kubernetes.

Confundir "el operador vive dentro del clúster" con "no necesita ningún permiso" (de seguridad, sutil). Qué pasa: alguien interpreta la tabla de seguridad como si ArgoCD/Flux no necesitaran ningún tipo de credencial. Por qué pasa: la fila dice "nadie externo tiene credenciales de escritura", y es fácil leerlo como "no hace falta ninguna credencial". Cómo detectarlo: si crees que ArgoCD no necesita ningún tipo de acceso configurado. Cómo corregirlo: el operador sí necesita permisos —un ServiceAccount de Kubernetes con un Role/ClusterRole que le permita crear, actualizar y borrar los recursos que administra dentro del clúster—, y también credenciales de lectura hacia el repositorio de Git (si es privado). Lo que elimina es la necesidad de credenciales de escritura externas hacia el destino, viajando desde un sistema fuera del clúster — no elimina la necesidad de permisos en general.

Creer que esta guía "no es GitOps de verdad" por ser push-based (ya visto en el Módulo 1, reforzado aquí). Qué pasa: alguien, ahora con el detalle técnico completo de pull, vuelve a dudar de si el pipeline de Andes Cargo "cuenta" como GitOps. Por qué pasa: el ejemplo de Kubernetes es el más citado en la industria cuando alguien dice "GitOps", y es fácil asumir que es el único válido. Cómo detectarlo: si después de esta lección sigues pensando que push es "GitOps de segunda categoría". Cómo corregirlo: la tabla de las cuatro propiedades de arriba lo confirma con precisión — las cuatro se cumplen en ambos mecanismos. Push y pull son dos implementaciones técnicas válidas del mismo principio, no una versión "completa" y otra "incompleta" de GitOps.


Ejercicios

Ejercicio 1 — Dirección del movimiento y credenciales, sin ayuda. Sin mirar esta lección, dibuja (en papel o en texto) las dos flechas de credenciales: ¿hacia dónde viajan las credenciales de escritura en push, y hacia dónde en pull?

Ver solución

Push: las credenciales viajan hacia afuera del sistema de CI, hacia adentro de AWS — el pipeline (externo a AWS) necesita autenticarse contra AWS para poder escribir ahí. Pull: no hay credenciales de escritura que viajen entre sistemas — el operador GitOps ya corre dentro del clúster que administra, así que usa el ServiceAccount con el que ya está autenticado localmente, sin necesitar que ninguna credencial "entre" desde afuera. La única credencial que sí cruza una frontera en pull es de lectura, del operador hacia el repositorio Git — nunca de escritura hacia el clúster.

Ejercicio 2 — Aplica la distinción a un escenario nuevo. Un colega te dice: "quiero desplegar mi aplicación de Kubernetes automáticamente cuando fusiono un PR, usando GitHub Actions con un kubectl apply dentro del workflow, en vez de instalar ArgoCD". ¿Ese diseño es push o pull? Justifica.

Ver solución

Es push-based, aunque el destino sea un clúster de Kubernetes. Lo que define el mecanismo no es "si el destino es Kubernetes o no" — es quién inicia el movimiento y desde dónde. Un workflow de GitHub Actions que corre kubectl apply está corriendo fuera del clúster (en un runner de GitHub), y necesita credenciales (un kubeconfig con acceso al clúster) que viajan hacia adentro cuando el pipeline se dispara por un evento de push/merge — exactamente la misma forma que apply.yml de esta guía, solo que el destino es un clúster de Kubernetes en vez de AWS vía Terraform. Es un diseño push válido y de hecho común en la práctica — la elección de usar ArgoCD/Flux en vez de esto es, precisamente, la elección de moverse a pull para ese mismo destino.

Ejercicio 3 — Explica por qué esta guía no puede volverse "pull" sin cambiar de destino. En dos o tres frases, explica por qué el pipeline de Andes Cargo —que administra S3, DynamoDB, IAM y Lambda vía Terraform— no podría convertirse en pull-based simplemente instalando ArgoCD.

Ver solución

Una explicación completa suena, más o menos, así: "ArgoCD y Flux son operadores que corren dentro de un clúster de Kubernetes, y su mecanismo de pull depende de que exista ese clúster como destino — 'vivir dentro del destino que administran' es literalmente la propiedad que elimina la necesidad de credenciales externas. La infraestructura de Andes Cargo (S3, DynamoDB, IAM, Lambda) no es un clúster de Kubernetes: es un conjunto de servicios de AWS administrados vía API, sin ningún lugar 'dentro' del cual un operador pudiera correr y observar continuamente. Para que este pipeline fuera pull-based, necesitaría existir algo corriendo permanentemente contra la cuenta de AWS observando el estado — un patrón que existe (algunos productos comerciales lo ofrecen), pero que no es el mecanismo estándar ni ampliamente adoptado que sí lo es ArgoCD/Flux para Kubernetes."


Resumen y siguiente paso

En esta lección cerraste el hilo abierto en el Módulo 1: confirmaste, con un diagrama de secuencia y una tabla de implicaciones de seguridad concreta, que push-based (el pipeline de esta guía) y pull-based (ArgoCD/Flux) son dos mecanismos técnicos genuinamente distintos —quién inicia el movimiento, hacia dónde viajan las credenciales, con qué latencia se aplica un cambio— que cumplen exactamente las mismas cuatro propiedades de GitOps. Entendiste por qué Kubernetes en producción tiende hacia pull (elimina una categoría entera de riesgo de credenciales) sin que eso convierta a push en una implementación de segunda categoría.

Antes de avanzar deberías poder: dibujar de memoria la dirección de las credenciales en ambos mecanismos; explicar la diferencia de latencia entre un pipeline reactivo y un operador con interval; y defender, con la tabla de las cuatro propiedades, por qué el pipeline de Andes Cargo es GitOps completo aunque sea push.

La lección 5 se aleja de GitOps en sí y entra a un territorio nuevo: qué pasa con el tráfico de usuarios reales cuando una aplicación se despliega — blue/green, canary, rolling deploys — un problema que ni push ni pull resuelven por sí solos, porque vive un nivel más abajo, en cómo se reemplazan las versiones de un artefacto corriendo.

Recursos

  1. Weaveworks Blog — What Is GitOps, Really? — el origen del término, ya citado en el Módulo 1, lección 4, base de la definición de las cuatro propiedades usadas en esta lección.
  2. Argo CD — Documentation — documentación oficial, incluida la sección de syncPolicy.automated y selfHeal referenciada en esta lección.
  3. Flux — Concepts — documentación oficial del mecanismo de reconciliación continua de Flux.
  4. GitHub Docs — About continuous deployment — el mecanismo push que esta guía implementó en los Módulos 3 y 5, punto de comparación de esta lección.
  5. terraform-and-iac-guide, Módulo 4 (gestión de secretos y credenciales de AWS) — el fundamento de por qué OIDC (Módulo 4 de esta guía) es la respuesta de push al problema de seguridad que pull resuelve por diseño.