StackPractices
advanced Por Mathias Paulenko

Asegurar y Observar Microservicios con un Service Mesh

Cómo desplegar Istio o Linkerd para agregar mTLS, gestión de tráfico, observabilidad y enforcement de políticas a microservicios sin cambiar código de aplicación.

Visión general

Los microservicios se comunican a través de la red, y la red no es confiable. Cada llamada inter-servicio cruza límites de pod, límites de nodo y potencialmente límites de cluster. Sin encriptación, atacantes con acceso a la red pueden leer o modificar tráfico. Sin identidad, cualquier servicio comprometido puede impersonar a otro. Sin observabilidad, debuggear un request que atraviesa 10 servicios es casi imposible.

Un service mesh resuelve estos problemas insertando un proxy — un sidecar container — al lado de cada pod de aplicación. Todo el tráfico entrante o saliente del pod fluye a través del sidecar. El sidecar maneja mTLS mutuo, enrutamiento de tráfico, retries, timeouts, métricas y políticas de acceso. El código de aplicación permanece completamente inconsciente. Aqui se explica como conceptos de service mesh, despliegue de Istio, políticas de tráfico y observabilidad.

Cuándo usarlo

Usa esta receta cuando:

  • Ejecutando 10+ microservicios en Kubernetes con comunicación inter-servicio compleja
  • Requiriendo encriptación para todo el tráfico servicio-a-servicio sin modificar aplicaciones
  • Implementando despliegues canary, A/B testing o mirroring de tráfico entre versiones de servicios
  • Necesitando observabilidad unificada (métricas, logs, traces) a través de todos los microservicios
  • Haciendo enforcement de políticas de acceso (ej. “el servicio de pagos solo puede hablar con billing y fraud detection”)

Solución

Instalación de Istio (istioctl)

istioctl install --set profile=default -y

kubectl label namespace default istio-injection=enabled

kubectl rollout restart deployment -n default

Enrutamiento de Tráfico con VirtualService

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: user-service-route
spec:
  hosts:
    - user-service
  http:
    - match:
        - headers:
            x-canary:
              exact: "true"
      route:
        - destination:
            host: user-service
            subset: v2
          weight: 100
    - route:
        - destination:
            host: user-service
            subset: v1
          weight: 90
        - destination:
            host: user-service
            subset: v2
          weight: 10

---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: user-service-dr
spec:
  host: user-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 50
    outlierDetection:
      consecutiveErrors: 5
      interval: 30s
      baseEjectionTime: 30s
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2

mTLS con PeerAuthentication

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: default
spec:
  mtls:
    mode: STRICT

---
# Permitir solo servicios específicos a acceder payment-service
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payment-policy
  namespace: default
spec:
  selector:
    matchLabels:
      app: payment-service
  action: ALLOW
  rules:
    - from:
        - source:
            principals:
              - "cluster.local/ns/default/sa/order-service"
              - "cluster.local/ns/default/sa/billing-service"

Explicación

  • Sidecar proxy: Envoy corre como sidecar en cada pod. Intercepta todo el tráfico de red vía reglas de iptables. Las aplicaciones aún hablan a localhost:8080, pero Envoy enruta, encripta y loguea el request real. El código de aplicación no requiere cambios.
  • Mutual TLS (mTLS): el sidecar proporciona un certificado para probar su identidad y valida el certificado del peer. El tráfico está encriptado en tránsito y autenticado en ambos extremos. Incluso dentro del mismo cluster, los servicios no pueden impersonarse entre sí sin robar un certificado.
  • Gestión de tráfico: VirtualService define reglas de enrutamiento — despliegues canary, retries, timeouts, inyección de fallos. Las políticas de tráfico son declarativas y versionadas en Git.
  • Observabilidad: Istio agrega esto en Kiali (topología), Grafana (métricas) y Jaeger (traces). Ves el grafo completo de servicios sin agregar instrumentación a las aplicaciones.

Variantes

FeatureIstioLinkerdConsul ConnectCilium Service Mesh
ComplejidadAltaBajaMediaMedia
PerformanceBuenaExcelenteBuenaExcelente (eBPF)
mTLS
Enrutamiento de tráficoCompletoBásicoBásicoBásico
Uso de recursosMayorMenorMediaBajo

Lo que funciona

  • Empieza con mTLS permisivo, luego enforce estricto: Después de validar flujos de tráfico, cambia a STRICT para rechazar conexiones no encriptadas. El modo estricto repentino puede romper servicios que no tienen sidecars.
  • Define service accounts por workload: las cuentas de servicio de Kubernetes se mapean a identidades de Istio. Esto habilita políticas de autorización granulares.
  • Configura retry budgets, no solo retries: retries ingenuos pueden amplificar fallos. Retries ilimitados crean retry storms.
  • Usa circuit breakers en cada llamada saliente: Si un servicio downstream retorna 5xx en el 50% de requests durante 30 segundos, échalo durante 30 segundos. Esto previene fallos en cascada.
  • Monitorea el uso de recursos del sidecar: Envoy consume CPU y memoria. Setea resource requests/limits en el sidecar. En servicios de alto throughput, el sidecar puede convertirse en el bottleneck antes que la aplicación. Profilea y tunea la concurrencia del proxy.

Errores comunes

  • Olvidar inyección de sidecar: un pod sin sidecar bypassa el mesh completamente. Su tráfico no está encriptado, no es observado y no tiene restricciones. Siempre verifica la inyección con kubectl get pod -o yaml | grep istio-proxy.
  • Políticas de autorización demasiado permisivas: una política ALLOW * por defecto derrota el propósito. Empieza con DENY all explícito, luego agrega reglas ALLOW para paths legítimos. Zero-trust significa denegar por defecto.
  • Ignorar ordering de startup: durante rolling updates, pods antiguos sin sidecar pueden hablar con pods nuevos con mTLS estricto.
  • Sin control de egress: por defecto, el tráfico mesh-internal está controlado pero el egress (APIs externas, bases de datos) no.

Preguntas frecuentes

Instalación de Linkerd (CLI)
# Instalar control plane de Linkerd
linkerd install --crd-only | kubectl apply -f -
linkerd install | kubectl apply -f -

# Verificar instalación
linkerd check

# Agregar mesh a un namespace
kubectl annotate namespace default linkerd.io/inject=enabled

# Reiniciar deployments
kubectl rollout restart deployment -n default
Traffic Mirroring para Shadow Testing
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: payment-mirror
spec:
  hosts:
    - payment-service
  http:
    - route:
        - destination:
            host: payment-service
            subset: v1
          weight: 100
      mirror:
        host: payment-service
        subset: v2
      mirrorPercentage:
        value: 100.0
Fault Injection para Resilience Testing
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: order-fault-injection
spec:
  hosts:
    - order-service
  http:
    - match:
        - headers:
            x-test-fault:
              exact: "true"
      fault:
        delay:
          percentage:
            value: 50
          fixedDelay: 5s
        abort:
          percentage:
            value: 10
          httpStatus: 503
      route:
        - destination:
            host: order-service
            subset: v1
Observabilidad con Kiali y Prometheus
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: istio-metrics
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: mesh
  endpoints:
    - port: http-monitoring
      interval: 15s
      path: /stats/prometheus
---
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: mesh-observability
  namespace: istio-system
spec:
  accessLogging:
    - providers:
        - name: envoy
  tracing:
    - providers:
        - name: jaeger
      randomSamplingPercentage: 10.0
  metrics:
    - providers:
        - name: prometheus
Egress Gateway para Control de APIs Externas
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-api
spec:
  hosts:
    - api.stripe.com
  ports:
    - number: 443
      name: https
      protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: egress-stripe
spec:
  hosts:
    - api.stripe.com
  http:
    - route:
        - destination:
            host: api.stripe.com
            port:
              number: 443
      timeout: 10s
      retries:
        attempts: 3
        perTryTimeout: 3s
        retryOn: 5xx,reset,connect-failure