Pipeline GitOps de nivel productivo sobre AWS EKS. Automatiza el ciclo de vida completo del software — desde el commit hasta el despliegue en Kubernetes. Git es la única fuente de verdad para código, infraestructura, configuración y accesos.
| Problema | Solución |
|---|---|
| Despliegues manuales propensos a error | Pipeline Jenkins de 7 stages — 100% automatizado |
| Acceso inseguro al cluster EKS | IAM Role asumible + sts:AssumeRole — cero credenciales estáticas |
| Infraestructura no reproducible | Terraform modular con backend S3 — apply recrea todo desde cero |
| Configuración manual de servidores | Ansible via AWS SSM — sin SSH, sin bastión, sin IP pública |
git push → PR → merge main
│
Jenkins Pipeline AWS
──────────────── ┌──────────────────────┐
1. pytest │ VPC 10.0.0.0/16 │
2. docker build │ ├─ private subnets │
3. push ECR │ │ worker-node ×2 │
4. terraform apply ──► │ └─ public subnets │
5. ansible SSM │ NAT Gateway │
6. kubectl rollout │ │
──────────────── │ EKS gitops-stack-prod │
│ │ 2 réplicas · multi-AZ │
└──────────────► │ self-healing · TLS │
└──────────────────────┘
| Layer | Tool | Role |
|---|---|---|
| App | Python / Flask | API REST — / /health |
| Container | Docker | Imagen optimizada por capas · tag BUILD_NUMBER |
| Registry | AWS ECR | Registry privado — pull solo con IAM |
| CI/CD | Jenkins on-premise | Pipeline declarativo — Jenkinsfile versionado |
| IaC | Terraform 1.9 | VPC · EKS · IAM · KMS · backend S3 |
| Config | Ansible + AWS SSM | Hardening y monitoring sin SSH |
| Orchestration | AWS EKS 1.35 | Cluster gestionado · multi-AZ |
| Access | IAM Role + STS | sts:AssumeRole — sesiones de 1h |
| Observability | CloudWatch · Grafana | Container Insights · logs 90d |
| Audit | CloudTrail | Cada acción AWS registrada con timestamp |
| Stage | Acción | Si falla |
|---|---|---|
| Test | pytest tests/ — fail fast |
Pipeline aborts |
| Build | docker build con layer cache |
Pipeline aborts |
| Push ECR | Tag :{BUILD_NUMBER} + push |
Pipeline aborts |
| Terraform | plan → aprobación manual → apply |
Requiere intervención |
| Ansible SSM | common · security · monitoring | ignore_errors en telnet |
| Kubernetes | sts:AssumeRole → kubectl apply → rollout |
Pipeline aborts |
Ningún usuario tiene acceso directo al cluster. Todo pasa por eks-admin-role.
liquenson-cli ─┐
├─► sts:AssumeRole ─► eks-admin-role ─► EKS cluster
Jenkins ─┘ (1h TTL) (Terraform managed)
# Access Entry apunta al ROL, nunca al usuario
resource "aws_eks_access_entry" "admin" {
principal_arn = aws_iam_role.eks_admin.arn
type = "STANDARD"
}CloudTrail audita cada jenkins-deploy-{BUILD_NUMBER} con rol, timestamp y región.
AWS eu-west-1
├── VPC 10.0.0.0/16
│ ├── private subnets 10.0.1.0/24 · 10.0.2.0/24 (workers — sin IP pública)
│ └── public subnets 10.0.101.0/24 · 10.0.102.0/24 (load balancers)
├── EKS gitops-stack-prod K8s 1.35
│ └── Node Group 2× t3.small · SSM enabled · min 1 / max 3
├── ECR gitops-stack (privado)
├── IAM eks-admin-role + 5 grupos + 22 usuarios (users.tf)
├── KMS alias/eks/gitops-stack-prod (secrets cifrados)
├── CloudWatch Container Insights · log groups 90d
└── S3 devops-lab-tfstate-538079272432 (Terraform backend)
IAM groups gestionados como código en users.tf:
| Group | Policy | Members |
|---|---|---|
devops-team |
EKS + ECR + CloudWatch | dev-kevin, dev-wesley, dev-ruben, dev-pelegrino, dev-aisa, dev-ismael, dev-fermme |
developers |
ECR PowerUser + CW Logs | dev-yolanda, dev-marcus, dev-elena, dev-william |
security-team |
IAM ReadOnly | sec-maria, sec-john, sec-anna |
monitoring-team |
CloudWatch ReadOnly | ops-pedro, ops-sofia, ops-james |
data-team |
S3 Full + RDS ReadOnly | data-luis, data-nina, data-alex |
Los nodos EKS corren Amazon Linux 2023 en subredes privadas. Ansible los configura sin SSH ni bastión usando community.aws.aws_ssm como connection plugin.
| Role | Tasks |
|---|---|
common |
dnf update · paquetes base · timezone · usuario deploy · límites archivos |
security |
SSH hardening · firewalld (HTTPS+SSH+6443) · dnf-automatic |
monitoring |
CloudWatch agent · métricas 60s · /var/log/messages + /var/log/secure |
Fix en producción:
immediate: yesen firewalld mantiene la sesión SSM activa durante el hardening. Sin esto el nodo pierde conexión al activar el firewall.
# Infraestructura completa desde cero
cd terraform
terraform init
terraform apply
# Conectar kubectl
aws eks update-kubeconfig --region eu-west-1 --name gitops-stack-prod
# Verificar
kubectl get nodes
kubectl get pods -A# Destroy seguro — elimina Load Balancers antes del destroy
bash scripts/pre-destroy.sh
cd terraform && terraform destroy -auto-approvegit checkout -b feat/mi-cambio
git commit -m "feat: descripción"
git push origin feat/mi-cambio
# → Pull Request → merge → Jenkins pipeline automáticomain tiene branch protection activa. Push directo bloqueado.
gitops-stack/
├── app/ # Flask API
├── tests/ # pytest
├── k8s/ # Deployment + Service manifests
├── terraform/
│ ├── main.tf # VPC · EKS · IAM Role · Access Entries · KMS
│ ├── users.tf # 5 grupos + 22 usuarios IAM como código
│ ├── variables.tf
│ └── outputs.tf
├── ansible/
│ ├── roles/
│ │ ├── common/
│ │ ├── security/ # firewalld con immediate:yes para SSM
│ │ └── monitoring/ # CloudWatch agent
│ ├── site.yml
│ └── inventory.yml # community.aws.aws_ssm
├── scripts/
│ └── pre-destroy.sh
├── Jenkinsfile # 7-stage declarative pipeline
└── Dockerfile # python:3.11-slim · layer cache optimizado
| Principio | Implementación |
|---|---|
| GitOps | Git es la única fuente de verdad — nada existe sin un commit |
| Immutable | Nueva imagen por commit — nunca modificación en caliente |
| Zero-SSH | Ansible via SSM — sin bastiones, sin claves SSH, sin IPs públicas |
| Least Privilege | IAM con mínimo privilegio — roles, no usuarios directos |
| Fail Fast | Pipeline se detiene ante cualquier fallo de tests |
| Auditability | Cada deploy vinculado a commit + BUILD_NUMBER + usuario + timestamp |
Developed by Liquenson · LRA Cloud Operations · Las Palmas de Gran Canaria