Skip to content
English
On this page

Ejercicio: Aplicación Escalable con EKS, Aurora y WAF

Parte 1: Configuración de EKS y Base de Infraestructura

Escenario

Implementaremos una aplicación web escalable que incluye:

  • Cluster EKS para orquestación de contenedores
  • Aurora PostgreSQL para base de datos
  • WAF para seguridad
  • Load Balancer y Auto Scaling

Estructura del Proyecto

eks-app/
├── infrastructure/
│   ├── terraform/
│   │   ├── eks/
│   │   │   ├── main.tf
│   │   │   ├── variables.tf
│   │   │   └── outputs.tf
│   │   ├── vpc/
│   │   │   ├── main.tf
│   │   │   └── variables.tf
│   │   └── modules/
│   │       └── networking/
│   │           └── main.tf
│   │
│   ├── kubernetes/
│   │   ├── base/
│   │   │   ├── namespace.yaml
│   │   │   └── secrets.yaml
│   │   ├── deployments/
│   │   │   └── app.yaml
│   │   └── services/
│   │       └── app-service.yaml
│   │
│   └── scripts/
│       ├── setup-eks.sh
│       └── validate-cluster.sh

├── app/
│   ├── backend/
│   │   ├── src/
│   │   ├── Dockerfile
│   │   └── requirements.txt
│   └── frontend/
│       ├── src/
│       ├── Dockerfile
│       └── package.json

└── docs/
    ├── setup.md
    └── architecture.md

1. Configuración de VPC y Networking

1.1 Terraform VPC

hcl
# infrastructure/terraform/vpc/main.tf
provider "aws" {
  region = var.aws_region
}

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  
  name = "eks-vpc"
  cidr = "10.0.0.0/16"
  
  azs             = ["us-east-1a", "us-east-1b", "us-east-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
  
  enable_nat_gateway = true
  single_nat_gateway = false
  
  tags = {
    Environment = var.environment
    Project     = "EKS-Aurora-Demo"
  }
  
  private_subnet_tags = {
    "kubernetes.io/cluster/${var.cluster_name}" = "shared"
    "kubernetes.io/role/internal-elb"           = "1"
  }
  
  public_subnet_tags = {
    "kubernetes.io/cluster/${var.cluster_name}" = "shared"
    "kubernetes.io/role/elb"                    = "1"
  }
}

1.2 Variables de VPC

hcl
# infrastructure/terraform/vpc/variables.tf
variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-east-1"
}

variable "environment" {
  description = "Environment name"
  type        = string
  default     = "production"
}

variable "cluster_name" {
  description = "Name of the EKS cluster"
  type        = string
  default     = "eks-demo-cluster"
}

2. Configuración de EKS

2.1 Terraform EKS

hcl
# infrastructure/terraform/eks/main.tf
provider "aws" {
  region = var.aws_region
}

module "eks" {
  source = "terraform-aws-modules/eks/aws"
  
  cluster_name    = var.cluster_name
  cluster_version = "1.27"
  
  vpc_id          = var.vpc_id
  subnet_ids      = var.private_subnet_ids
  
  eks_managed_node_groups = {
    primary = {
      desired_size = 2
      min_size     = 1
      max_size     = 4
      
      instance_types = ["t3.medium"]
      capacity_type  = "ON_DEMAND"
      
      update_config = {
        max_unavailable_percentage = 50
      }
      
      labels = {
        Environment = var.environment
        NodeGroup  = "primary"
      }
    }
  }
  
  cluster_endpoint_private_access = true
  cluster_endpoint_public_access  = true
  
  manage_aws_auth_configmap = true
}

2.2 Script de Setup EKS

bash
#!/bin/bash
# infrastructure/scripts/setup-eks.sh

# Variables
CLUSTER_NAME="eks-demo-cluster"
REGION="us-east-1"

# Actualizar kubeconfig
aws eks update-kubeconfig --name $CLUSTER_NAME --region $REGION

# Verificar nodos
kubectl get nodes

# Crear namespace
kubectl create namespace production

# Aplicar configuraciones base
kubectl apply -f infrastructure/kubernetes/base/

# Verificar estado del cluster
kubectl get componentstatuses

3. Configuración de Kubernetes Base

3.1 Namespace

yaml
# infrastructure/kubernetes/base/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    name: production
    environment: production

3.2 Configuración de Recursos Base

yaml
# infrastructure/kubernetes/base/resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
  namespace: production
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "20"

3.3 Políticas de Red

yaml
# infrastructure/kubernetes/base/network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Verificación Parte 1

1. Verificar VPC

  • [ ] Subredes creadas
  • [ ] NAT Gateways funcionando
  • [ ] Tablas de ruteo configuradas
  • [ ] Tags correctos

2. Verificar EKS

  • [ ] Cluster creado
  • [ ] Nodos registrados
  • [ ] kubectl configurado
  • [ ] Endpoints accesibles

3. Verificar Kubernetes

  • [ ] Namespace creado
  • [ ] Políticas aplicadas
  • [ ] Recursos configurados
  • [ ] Logs disponibles

Troubleshooting Común

Errores de VPC

  1. Verificar CIDR blocks
  2. Revisar NAT Gateways
  3. Verificar tags de subredes

Errores de EKS

  1. Verificar IAM roles
  2. Revisar grupos de seguridad
  3. Verificar conectividad

Errores de Kubernetes

  1. Verificar kubeconfig
  2. Revisar estado de nodos
  3. Verificar políticas de red

Script de Validación

bash
#!/bin/bash
# infrastructure/scripts/validate-cluster.sh

echo "Validando VPC..."
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=eks-vpc"

echo "Validando EKS..."
aws eks describe-cluster --name eks-demo-cluster

echo "Validando Kubernetes..."
kubectl cluster-info
kubectl get nodes
kubectl get ns

# Verificar métricas básicas
kubectl top nodes

# Verificar componentes
kubectl get componentstatuses

Parte 2: Configuración de Aurora PostgreSQL e Integración

1. Configuración de Aurora PostgreSQL

1.1 Terraform Aurora

hcl
# infrastructure/terraform/aurora/main.tf
module "aurora" {
  source = "terraform-aws-modules/rds-aurora/aws"

  name            = "eks-aurora-cluster"
  engine          = "aurora-postgresql"
  engine_version  = "13.8"
  instance_class  = "db.r5.large"
  
  instances = {
    primary = {}
    replica = {
      count = 1
    }
  }

  vpc_id                 = var.vpc_id
  db_subnet_group_name   = aws_db_subnet_group.aurora.name
  create_security_group  = true
  allowed_cidr_blocks    = var.private_subnet_cidrs

  database_name     = "appdb"
  master_username   = var.db_username
  master_password   = var.db_password

  backup_retention_period = 7
  preferred_backup_window = "02:00-03:00"
  
  enabled_cloudwatch_logs_exports = ["postgresql"]

  tags = {
    Environment = var.environment
    Project     = "EKS-Aurora-Demo"
  }
}

resource "aws_db_subnet_group" "aurora" {
  name       = "aurora-subnet-group"
  subnet_ids = var.private_subnet_ids
}

1.2 Secretos para Aurora

yaml
# infrastructure/kubernetes/secrets/aurora-secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: aurora-credentials
  namespace: production
type: Opaque
data:
  username: <base64-encoded-username>
  password: <base64-encoded-password>
  host: <base64-encoded-host>
  port: <base64-encoded-port>
  database: <base64-encoded-database>

1.3 ConfigMap para Aurora

yaml
# infrastructure/kubernetes/configmaps/aurora-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: aurora-config
  namespace: production
data:
  database.conf: |
    max_connections=200
    shared_buffers=4GB
    effective_cache_size=12GB
    maintenance_work_mem=1GB
    checkpoint_completion_target=0.9
    wal_buffers=16MB
    default_statistics_target=100
    random_page_cost=1.1
    effective_io_concurrency=200

2. Configuración de Conexión Segura

2.1 Security Group para Aurora

hcl
# infrastructure/terraform/aurora/security.tf
resource "aws_security_group" "aurora" {
  name_prefix = "aurora-security-group"
  vpc_id      = var.vpc_id

  ingress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [var.eks_security_group_id]
  }
}

2.2 IAM Role para Acceso

hcl
# infrastructure/terraform/iam/aurora-access.tf
resource "aws_iam_role" "aurora_access" {
  name = "eks-aurora-access"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "eks.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy" "aurora_access" {
  name = "aurora-access-policy"
  role = aws_iam_role.aurora_access.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "rds-db:connect",
          "rds:DescribeDBClusters"
        ]
        Resource = [module.aurora.cluster_arn]
      }
    ]
  })
}

3. Configuración de Conexión desde EKS

3.1 Service Account para Aurora

yaml
# infrastructure/kubernetes/serviceaccounts/aurora-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: aurora-access
  namespace: production
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT_ID:role/eks-aurora-access

3.2 Deployment con Aurora Connection

yaml
# infrastructure/kubernetes/deployments/app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      serviceAccountName: aurora-access
      containers:
      - name: backend
        image: app-backend:latest
        env:
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: aurora-credentials
              key: host
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: aurora-credentials
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: aurora-credentials
              key: password
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 20

4. Monitoreo de Aurora

4.1 CloudWatch Métricas

hcl
# infrastructure/terraform/monitoring/aurora-monitoring.tf
resource "aws_cloudwatch_metric_alarm" "aurora_cpu" {
  alarm_name          = "aurora-high-cpu"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "2"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/RDS"
  period              = "300"
  statistic           = "Average"
  threshold           = "80"
  alarm_description   = "High CPU utilization"
  alarm_actions       = [aws_sns_topic.alerts.arn]

  dimensions = {
    DBClusterIdentifier = module.aurora.cluster_id
  }
}

4.2 Dashboard para Aurora

json
// infrastructure/monitoring/aurora-dashboard.json
{
  "widgets": [
    {
      "type": "metric",
      "properties": {
        "metrics": [
          ["AWS/RDS", "CPUUtilization", "DBClusterIdentifier", "${ClusterName}"],
          [".", "FreeableMemory", ".", "."],
          [".", "DatabaseConnections", ".", "."]
        ],
        "period": 300,
        "stat": "Average",
        "region": "us-east-1",
        "title": "Aurora Cluster Metrics"
      }
    }
  ]
}

Verificación Parte 2

1. Verificar Aurora

  • [ ] Cluster creado
  • [ ] Réplicas funcionando
  • [ ] Backups configurados
  • [ ] Logs exportados

2. Verificar Conexión

  • [ ] Secretos creados
  • [ ] Service Account configurado
  • [ ] IAM roles asignados
  • [ ] Conexión probada

3. Verificar Monitoreo

  • [ ] Métricas recolectadas
  • [ ] Alarmas configuradas
  • [ ] Dashboard creado
  • [ ] Logs accesibles

Troubleshooting Común

Errores de Aurora

  1. Verificar estado del cluster
  2. Revisar logs de PostgreSQL
  3. Verificar conexiones activas

Errores de Conexión

  1. Verificar credenciales
  2. Revisar grupos de seguridad
  3. Verificar IAM roles

Errores de Monitoreo

  1. Verificar métricas
  2. Revisar configuración de alarmas
  3. Verificar permisos de CloudWatch

Scripts de Validación

Validar Aurora

bash
#!/bin/bash
# scripts/validate-aurora.sh

echo "Verificando cluster Aurora..."
aws rds describe-db-clusters --db-cluster-identifier eks-aurora-cluster

echo "Verificando conexión..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -U $DB_USER -d appdb -c "\dt"

echo "Verificando métricas..."
aws cloudwatch get-metric-statistics \
    --namespace AWS/RDS \
    --metric-name CPUUtilization \
    --dimensions Name=DBClusterIdentifier,Value=eks-aurora-cluster \
    --start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ" -d "1 hour ago") \
    --end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") \
    --period 300 \
    --statistics Average

Parte 3: Seguridad con WAF e Integración Final

1. Configuración de WAF

1.1 Terraform WAF

hcl
# infrastructure/terraform/waf/main.tf
resource "aws_wafv2_web_acl" "main" {
  name        = "eks-protection"
  description = "WAF rules for EKS cluster"
  scope       = "REGIONAL"

  default_action {
    allow {}
  }

  rule {
    name     = "RateLimit"
    priority = 1

    override_action {
      none {}
    }

    statement {
      rate_based_statement {
        limit              = 2000
        aggregate_key_type = "IP"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name               = "RateLimitRule"
      sampled_requests_enabled  = true
    }
  }

  rule {
    name     = "SQLInjectionProtection"
    priority = 2

    override_action {
      none {}
    }

    statement {
      sql_injection_match_statement {
        field_to_match {
          body {}
        }
        text_transformation {
          priority = 1
          type     = "URL_DECODE"
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name               = "SQLInjectionRule"
      sampled_requests_enabled  = true
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name               = "EKSProtectionMetrics"
    sampled_requests_enabled  = true
  }
}

1.2 Asociación con ALB

hcl
# infrastructure/terraform/waf/alb.tf
resource "aws_wafv2_web_acl_association" "alb" {
  resource_arn = var.alb_arn
  web_acl_arn  = aws_wafv2_web_acl.main.arn
}

resource "aws_wafv2_logging_configuration" "main" {
  log_destination_configs = [aws_kinesis_firehose_delivery_stream.waf_logs.arn]
  resource_arn           = aws_wafv2_web_acl.main.arn
}

2. Seguridad Adicional

2.1 Network Policies

yaml
# infrastructure/kubernetes/security/network-policies.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: app-network-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432

2.2 Pod Security Policies

yaml
# infrastructure/kubernetes/security/pod-security.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
spec:
  privileged: false
  seLinux:
    rule: RunAsAny
  runAsUser:
    rule: MustRunAsNonRoot
  fsGroup:
    rule: RunAsAny
  volumes:
  - 'configMap'
  - 'emptyDir'
  - 'secret'

3. Integración Final

3.1 Ingress Controller

yaml
# infrastructure/kubernetes/ingress/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  namespace: production
  annotations:
    kubernetes.io/ingress.class: "alb"
    alb.ingress.kubernetes.io/scheme: "internet-facing"
    alb.ingress.kubernetes.io/target-type: "ip"
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: backend-service
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80

3.2 Service Mesh Configuration

yaml
# infrastructure/kubernetes/istio/virtual-service.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: app-routes
  namespace: production
spec:
  hosts:
  - "app.example.com"
  gateways:
  - app-gateway
  http:
  - match:
    - uri:
        prefix: /api
    route:
    - destination:
        host: backend-service
        port:
          number: 80
    retries:
      attempts: 3
      perTryTimeout: 2s
    timeout: 5s

4. Monitoreo y Logging

4.1 CloudWatch Logs

hcl
# infrastructure/terraform/monitoring/logs.tf
resource "aws_cloudwatch_log_group" "waf_logs" {
  name              = "/aws/waf/eks"
  retention_in_days = 30

  tags = {
    Environment = var.environment
    Project     = "EKS-Aurora-Demo"
  }
}

resource "aws_kinesis_firehose_delivery_stream" "waf_logs" {
  name        = "aws-waf-logs-eks"
  destination = "s3"

  s3_configuration {
    role_arn   = aws_iam_role.firehose_role.arn
    bucket_arn = aws_s3_bucket.waf_logs.arn
  }
}

4.2 Prometheus y Grafana

yaml
# infrastructure/kubernetes/monitoring/prometheus-values.yaml
prometheus:
  prometheusSpec:
    serviceMonitorSelectorNilUsesHelmValues: false
    serviceMonitorSelector: {}
    serviceMonitorNamespaceSelector: {}
    podMonitorSelectorNilUsesHelmValues: false
    podMonitorSelector: {}
    podMonitorNamespaceSelector: {}

grafana:
  adminPassword: ${GRAFANA_PASSWORD}
  dashboardProviders:
    dashboardproviders.yaml:
      apiVersion: 1
      providers:
      - name: 'default'
        orgId: 1
        folder: ''
        type: file
        disableDeletion: false
        editable: true
        options:
          path: /var/lib/grafana/dashboards/default

5. Scripts de Despliegue

5.1 Deploy Final

bash
#!/bin/bash
# scripts/deploy-all.sh

# Variables
ENVIRONMENT="production"
CLUSTER_NAME="eks-demo-cluster"
REGION="us-east-1"

# Desplegar infraestructura
terraform init
terraform apply -auto-approve

# Configurar kubectl
aws eks update-kubeconfig --name $CLUSTER_NAME --region $REGION

# Aplicar configuraciones de Kubernetes
kubectl apply -f infrastructure/kubernetes/base/
kubectl apply -f infrastructure/kubernetes/security/
kubectl apply -f infrastructure/kubernetes/ingress/

# Desplegar aplicación
kubectl apply -f infrastructure/kubernetes/deployments/
kubectl apply -f infrastructure/kubernetes/services/

# Configurar monitoreo
helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
  -f infrastructure/kubernetes/monitoring/prometheus-values.yaml \
  -n monitoring --create-namespace

# Validar despliegue
./scripts/validate-deployment.sh

5.2 Validación Final

bash
#!/bin/bash
# scripts/validate-deployment.sh

echo "Validando WAF..."
aws wafv2 get-web-acl --name eks-protection --scope REGIONAL

echo "Validando EKS..."
kubectl get nodes
kubectl get pods -A

echo "Validando Aurora..."
aws rds describe-db-clusters --db-cluster-identifier eks-aurora-cluster

echo "Validando métricas..."
kubectl get pods -n monitoring

echo "Validando ingress..."
kubectl get ingress -A

Verificación Final

1. Verificar Seguridad

  • [ ] WAF configurado
  • [ ] Network Policies aplicadas
  • [ ] Pod Security activa
  • [ ] SSL/TLS configurado

2. Verificar Integración

  • [ ] Ingress funcionando
  • [ ] Service Mesh activo
  • [ ] Comunicación entre servicios
  • [ ] LoadBalancer configurado

3. Verificar Monitoreo

  • [ ] Logs centralizados
  • [ ] Métricas recolectadas
  • [ ] Dashboards configurados
  • [ ] Alertas activas

Troubleshooting Final

Problemas de Seguridad

  1. Verificar reglas WAF
  2. Revisar Network Policies
  3. Verificar certificados SSL

Problemas de Integración

  1. Verificar DNS
  2. Revisar Service Mesh
  3. Verificar LoadBalancer

Problemas de Monitoreo

  1. Verificar Prometheus
  2. Revisar logs
  3. Verificar métricas

Puntos Importantes

  1. Seguridad multinivel
  2. Monitoreo completo
  3. Alta disponibilidad
  4. Escalabilidad automática

La integración completa proporciona:

  1. Protección WAF contra ataques
  2. Políticas de red granulares
  3. Monitoreo avanzado
  4. Despliegue automatizado

Puntos clave para recordar:

  • La seguridad es multicapa
  • El monitoreo es crucial
  • La automatización reduce errores
  • La documentación es importante