Todos hemos visto el diagrama perfecto: un desarrollador hace push a main, se ejecutan los tests, se construye la imagen Docker, se despliega en Kubernetes y en minutos el cambio está en producción. Limpio. Automático. Elegante.
Antes de que ese pipeline funcione, alguien en tu equipo tuvo que resolver un rompecabezas de accesos, credenciales, configuraciones de red y permisos que fácilmente puede llevar semanas — no minutos. Y lo peor: cada acceso mal configurado es una puerta abierta a tu infraestructura de producción.
🧩Lo que ningún tutorial te muestra
Cualquier tutorial te muestra cómo escribir un archivo .github/workflows/deploy.yml con 30 líneas de YAML. Lo que ninguno muestra es todo lo que tiene que existir antes de que ese YAML funcione. Para que tu pipeline pueda desplegar en un cluster de EKS en una VPC privada, necesitás resolver tres accesos críticos:
Tres accesos. Tres conjuntos de credenciales. Tres vectores de ataque si se configuran mal.
🔒Conectar el pipeline a tu red privada
Si seguiste las buenas prácticas, tu cluster vive en subnets privadas — no es accesible desde internet. Correcto desde la perspectiva de seguridad. Problemático para el CI/CD: GitHub Actions corre en runners efímeros fuera de tu red y no puede hablar con tu cluster.
Hacer público el API server: terrible para la seguridad. Configurar VPN en el pipeline: complejo y frágil. Self-hosted runners dentro de tu VPC: otro servidor que mantener, parchar y monitorear.
Si elegís la ruta de VPN — la más común — tu pipeline empieza así solo para resolver la conectividad de red:
- name: Install OpenVPN run: sudo apt-get update && sudo apt-get install -y openvpn - name: Connect to VPN run: | echo "${{ secrets.VPN_CONFIG }}" > vpn.ovpn echo "${{ secrets.VPN_CA_CERT }}" > ca.crt echo "${{ secrets.VPN_CLIENT_CERT }}" > client.crt echo "${{ secrets.VPN_CLIENT_KEY }}" > client.key sudo openvpn --config vpn.ovpn \ --ca ca.crt --cert client.crt --key client.key \ --daemon sleep 15
Si los certificados expiran un viernes a las 6 PM, nadie despliega hasta el lunes. Los certificados VPN son un punto de falla que nadie recuerda hasta que producción está frenada.
🔑Autenticarse contra Kubernetes
Estás dentro de la red. Ahora necesitás que el pipeline pueda ejecutar comandos contra el cluster. La opción más segura es OIDC Federation — el pipeline asume un IAM Role sin Access Keys estáticas. Suena limpio. Para que funcione necesitás coordinar al menos 4 piezas diferentes entre AWS IAM y Kubernetes.
// Trust policy del IAM Role para GitHub Actions (OIDC) { "Statement": [{ "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringLike": { "token.actions.githubusercontent.com:sub": "repo:mi-org/mi-repo:ref:refs/heads/main" } } }] } # RBAC en Kubernetes - qué puede hacer el pipeline apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: deployer-role rules: - apiGroups: ["apps"] resources: ["deployments","replicasets"] verbs: ["get","list","watch","update","patch"]
Si cualquier pieza no encaja — y hay muchas piezas — el pipeline falla con un error críptico de Unauthorized que puede tardar horas en diagnosticar. No siempre es claro cuál de las 4 capas (OIDC, IAM, aws-auth, RBAC) es la que falló.
📦Push y Pull de imágenes Docker
Tu pipeline construye la imagen. Esa imagen necesita ir a un registry donde el cluster pueda descargarla. Son dos flujos de autenticación diferentes: el pipeline pushea, el cluster pullea. Si usás Amazon ECR, el token de autenticación dura 12 horas y necesitás renovarlo antes de cada push.
- name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v2 - name: Build and Push run: | docker build -t $REGISTRY/my-app:${{ github.sha }} . docker push $REGISTRY/my-app:${{ github.sha }} - name: Deploy to Kubernetes run: | kubectl set image deployment/my-app \ my-app=$REGISTRY/my-app:${{ github.sha }} \ -n production
El ECR repository tiene que existir con lifecycle policies configuradas para no acumular imágenes infinitas, con permisos de push para el rol del pipeline y permisos de pull para los nodos del cluster. Si usás cuentas AWS separadas por entorno, sumale Cross-Account Policies.
📜El panorama completo: 50+ líneas y semanas de config previa
Cuando juntás los 3 accesos en un solo pipeline, el resultado es esto — en la versión simplificada, sin tests, linting, security scanning, multi-environment ni rollback automático:
name: Deploy to Production on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # ACCESO 1: VPN (~15 líneas + 4 secrets) - name: Install and Connect VPN run: | sudo apt-get install -y openvpn echo "${{ secrets.VPN_CONFIG }}" > vpn.ovpn echo "${{ secrets.VPN_CA_CERT }}" > ca.crt echo "${{ secrets.VPN_CLIENT_CERT }}" > client.crt echo "${{ secrets.VPN_CLIENT_KEY }}" > client.key sudo openvpn --config vpn.ovpn \ --ca ca.crt --cert client.crt --key client.key --daemon sleep 15 # ACCESO 2: AWS + Kubernetes (~10 líneas + IAM/OIDC/RBAC previo) - name: Configure AWS (OIDC) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} aws-region: us-east-1 - name: Connect to EKS run: aws eks update-kubeconfig --name my-cluster --region us-east-1 # ACCESO 3: Registry (~10 líneas + ECR policies previas) - name: Login to ECR id: ecr uses: aws-actions/amazon-ecr-login@v2 # BUILD + DEPLOY - name: Build, Push and Deploy run: | docker build -t ${{ steps.ecr.outputs.registry }}/my-app:${{ github.sha }} . docker push ${{ steps.ecr.outputs.registry }}/my-app:${{ github.sha }} kubectl set image deployment/my-app \ my-app=${{ steps.ecr.outputs.registry }}/my-app:${{ github.sha }} \ -n production kubectl rollout status deployment/my-app -n production --timeout=300s - name: Disconnect VPN if: always() run: sudo killall openvpn || true
Pero el YAML es solo la punta del iceberg. Para que estas líneas funcionen, previamente necesitaste configurar todo esto:
| Qué configurar | Dónde |
|---|---|
| Servidor VPN desplegado y configurado | AWS VPC |
| Certificados VPN generados y distribuidos | Infra GitHub Secrets |
| OIDC Identity Provider | AWS IAM |
| IAM Role con trust policy específica | AWS IAM |
| aws-auth ConfigMap mapeado | Kubernetes |
| RBAC — ClusterRole + ClusterRoleBinding | Kubernetes |
| ECR Repository con lifecycle policies | AWS ECR |
| IAM Policy de pull en nodos del cluster | AWS IAM |
| 6+ secrets configurados en el repositorio | GitHub Settings |
Configurar todo esto correctamente le toma a un equipo experimentado entre 3 y 10 días hábiles. A un equipo que lo hace por primera vez, fácilmente 2 a 4 semanas. Y después viene el mantenimiento: certificados que expiran, tokens que rotan, APIs que se deprecan, versiones de Kubernetes que cambian. Cada incidente son horas de debugging y deploys frenados.
✨5 minutos reales con SleakOps
¿Y si toda esa infraestructura previa — la VPN, los roles IAM, el cluster, el registry, los permisos de RBAC — ya existiera configurada y segura? ¿Y si solo tuvieras que copiar un comando en tu pipeline?
name: Deploy to Production on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Deploy with SleakOps run: | sleakops deploy \ --app my-app \ --env production \ --image-tag ${{ github.sha }}
La CLI se encarga de conectarse a tu red privada, autenticarse contra el cluster, construir y pushear la imagen al registry, desplegar en Kubernetes y verificar que el rollout fue exitoso. Todo con credenciales temporales y menor privilegio por defecto. Y funciona igual en GitHub Actions, GitLab CI, Bitbucket Pipelines o cualquier sistema que pueda ejecutar bash.
| Pipeline manual | Con SleakOps |
|---|---|
| 50+ líneas de YAML solo para los 3 accesos | 1 comando: sleakops deploy |
| 6+ secrets que mantener y rotar manualmente | Sin secrets en el pipeline — credenciales temporales |
| Certificados VPN que expiran en el peor momento | Conectividad gestionada automáticamente |
| 3–10 días de config para un equipo experimentado | Funciona desde el primer deploy |
| Mantenimiento continuo de cada capa | Actualizaciones gestionadas por SleakOps |
| Solo GitHub Actions (config específica por plataforma) | GitHub, GitLab, Bitbucket o cualquier CLI |
Tu pipeline no debería ser un proyecto de infraestructura
La pregunta no es si tu equipo puede configurar todo esto manualmente. Seguramente puede. La pregunta es: ¿debería invertir semanas en plomería de infraestructura, o en construir producto?
Conocé SleakOps →