Implementación y gestión de tráfico con Istio en entornos nativos de la nube

Istio: Plataforma de malla de servicios para aplicaciones nativas de la nube

  1. Descripción general de Istio

1.1 ¿Qué es Istio?

Istio constituye una infraestructura de malla de servicios diseñada específicamente para orquestar y administrar la comunicación entre microservicios en arquitecturas nativas de la nube.

1.2 Características fundamentales

  • Observabilidad integrada del tráfico
  • Mecanismos de seguridad robustos
  • Gestión avanzada del flujo de datos

1.3 Capacidades principales

Mediante el patrón sidecar, se inyecta un proxy adyacente a cada servicio que habilita las siguientes funcionalidades:

  1. Descubrimiento de servicios: el proxy identifica los endpoints disponibles detrás de cada servicio y distribuye el tráfico según estrategias de balanceo configuradas.
  2. Aislamiento de instancias defectuosas.
  3. Protección del servicio: limitación de conexiones y solicitudes máximas.
  4. Fallo rápido y tiempos de espera configurables.
  5. Limitación de velocidad para endpoints específicos.
  6. Reintentos automáticos ante fallos de comunicación.
  7. Modificación dinámica de encabezados HTTP.
  8. Inyección de fallos para pruebas de resiliencia.
  9. Redirección de peticiones hacia otros destinos.
  10. Publicaciones graduales: distribución de tráfico por peso o contenido de la petición.
  11. Cifrado mutuo TLS entre cliente y servidor.
  12. Autorización granular de acceso.
  13. Registro automático de logs y detalles de cada petición.
  14. Instrumentación de trazas distribuidas.
  15. Generación de métricas y topología completa de la aplicación.

Todas estas funcionalidades se activan dinámicamente mediante configuración, sin necesidad de modificar el código de la aplicación.

1.4 Componentes arquitectónicos

1.4.1 Envoy (plano de datos)

Envoy se despliega como contenedor sidecar junto a cada servicio. Coordina todo el tráfico entrante y saliente dentro de la malla.

Características integradas:

  • Descubrimiento dinámico de servicios
  • Balanceo de carga
  • Terminación TLS
  • Proxy para HTTP/2 y gRPC
  • Circuit breaker
  • Verificación de salud
  • Despliegue gradual por porcentajes de tráfico
  • Inyección de fallos
  • Métricas detalladas

Extensiones de Istio sobre Envoy:

  • Control de tráfico
  • Resiliencia de red
  • Seguridad y autenticación
  • Extensiones basadas en WebAssembly

1.4.2 Istiod (plano de control)

Integra los componentes Pilot, Galley y Citadel. Gestiona el descubrimiento de servicios, la distribución de configuración y la administración de certificados.

  1. Instalación de Istio

2.1 Despliegue mediante Helm

# Registrar el repositorio oficial
helm repo add istio-repo https://istio-release.storage.googleapis.com/charts
helm repo update

# Descargar los charts necesarios
helm pull istio-base istio/base
helm pull istiod istio/istiod
helm pull istio-ingress istio/gateways

# Crear el namespace dedicado
kubectl create namespace istio-system

# Instalar los componentes base
helm install istio-base ./charts/base -n istio-system
helm install istiod ./charts/istiod -n istio-system
helm install istio-ingress ./charts/gateways -n istio-system
helm install istio-egress ./charts/egress -n istio-system

# Verificar la instalación
helm list -A
kubectl get pods -n istio-system
  1. Configuración y uso

3.1 Despliegue de servicios de ejemplo

Para demostrar las capacidades de Istio, se despliega una aplicación de ejemplo compuesta por varios microservicios:

apiVersion: v1
kind: Service
metadata:
  name: catalogo
  labels:
    app: catalogo
    servicio: catalogo
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: catalogo
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-catalogo
  labels:
    cuenta: catalogo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: catalogo-v1
  labels:
    app: catalogo
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: catalogo
      version: v1
  template:
    metadata:
      labels:
        app: catalogo
        version: v1
    spec:
      serviceAccountName: sa-catalogo
      containers:
      - name: catalogo-app
        image: registry.example.com/catalogo:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
apiVersion: v1
kind: Service
metadata:
  name: puntuacion
  labels:
    app: puntuacion
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: puntuacion
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-puntuacion
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: puntuacion-v1
  labels:
    app: puntuacion
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: puntuacion
      version: v1
  template:
    metadata:
      labels:
        app: puntuacion
        version: v1
    spec:
      serviceAccountName: sa-puntuacion
      containers:
      - name: puntuacion-app
        image: registry.example.com/puntuacion:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
apiVersion: v1
kind: Service
metadata:
  name: opiniones
  labels:
    app: opiniones
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: opiniones
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-opiniones
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: opiniones-v1
  labels:
    app: opiniones
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: opiniones
      version: v1
  template:
    metadata:
      labels:
        app: opiniones
        version: v1
    spec:
      serviceAccountName: sa-opiniones
      containers:
      - name: opiniones-app
        image: registry.example.com/opiniones:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: opiniones-v2
  labels:
    app: opiniones
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: opiniones
      version: v2
  template:
    metadata:
      labels:
        app: opiniones
        version: v2
    spec:
      serviceAccountName: sa-opiniones
      containers:
      - name: opiniones-app
        image: registry.example.com/opiniones:2.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
apiVersion: v1
kind: Service
metadata:
  name: tienda
  labels:
    app: tienda
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: tienda
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-tienda
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tienda-v1
  labels:
    app: tienda
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tienda
      version: v1
  template:
    metadata:
      labels:
        app: tienda
        version: v1
    spec:
      serviceAccountName: sa-tienda
      containers:
      - name: tienda-app
        image: registry.example.com/tienda:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

3.2 Inyección automática del sidecar

# Etiquetar el namespace para activar la inyección automática
kubectl label namespace <nombre_ns> istio-injection=enabled

3.3 Inyección manual del sidecar

# Generar el manifiesto con el sidecar incorporado
istioctl kube-inject -f manifiesto.yaml > manifiesto_con_sidecar.yaml
# Aplicar el manifiesto modificado
kubectl apply -f manifiesto_con_sidecar.yaml
  1. Observabilidad

4.1 Métricas

Istio genera métricas basadas en los cuatro indicadores dorados de monitoreo: latencia, tráfico, errores y saturación. Se distinguen tres niveles:

  • Métricas de gestión del proxy (configuración y salud)
  • Métricas a nivel de servicio
  • Métricas del plano de control

4.1.1 Métricas integradas

kubectl exec -ti -n <namespace> <nombre_pod> -c istio-proxy -- \
  pilot-agent request GET /stats/prometheus

4.1.2 Personalización de métricas

Modificar dimensiones de métricas existentes:

# Instalar los recursos personalizados
istioctl install -f configuracion-metricas.yaml
kubectl get istiooperator -n istio-system

# Agregar dimensiones bajo spec.values.telemetry.v2.prometheus
configOverride:
  gateway:
    metrics:
    - name: requests_total
      dimensions:
        host_destino: request.host
        metodo_http: request.method
      tags_to_remove:
      - response_flags
  inboundSidecar:
    metrics:
    - dimensions:
      host_destino: request.host
      metodo_http: request.method
  outboundSidecar:
    metrics:
    - dimensions:
      host_destino: request.host
      metodo_http: request.method

Definir métricas personalizadas nuevas:

# Agregar definición bajo spec.values.telemetry.v2.prometheus
configOverride:
  outboundSidecar:
    definitions:
    - name: contador_personalizado
      type: COUNTER
      value: "1"
    metrics:
    - name: contador_personalizado
      dimensions:
        origen: "'proxy'"

4.2 Trazas distribuidas

Los proxies Envoy generan automáticamente spans de rastreo. La aplicación únicamente necesita reenviar el contexto de la petición adecuado. Istio es compatible con múltiples sistemas de trazas como Zipkin, Jaeger, LightStep y Datadog. El operador controla la tasa de muestreo de las trazas generadas.

4.3 Registro de acceso

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: registro-malla
  namespace: istio-system
spec:
  accessLogging:
    - providers:
      - name: envoy
  1. Gestión de tráfico

5.1 Publicaciones graduales (segmentación de tráfico)

5.1.1 Definir subconjuntos de servicio

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: regla-opiniones
  namespace: entorno-pruebas
spec:
  host: opiniones
  subsets:
  - name: estable
    labels:
      version: v1
  - name: beta
    labels:
      version: v2
  - name: canario
    labels:
      version: v3

5.1.2 Distribución por proporción de tráfico

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-opiniones
  namespace: entorno-pruebas
spec:
  hosts:
  - opiniones
  http:
  - route:
    - destination:
        host: opiniones
        subset: estable
      weight: 70
    - destination:
        host: opiniones
        subset: beta
      weight: 30

5.1.3 Enrutamiento basado en contenido de la petición

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-opiniones
  namespace: entorno-pruebas
spec:
  hosts:
  - opiniones
  http:
  - match:
    - headers:
        User-Agent:
          regex: .*(Firefox/([\d.]+)).*
    route:
    - destination:
        host: opiniones
        subset: beta
  - route:
    - destination:
        host: opiniones
        subset: estable

5.1.4 Condiciones múltiples combinadas

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-frontend
  namespace: entorno-produccion
spec:
  hosts:
  - "*"
  gateways:
  - istio-system/gateway-produccion
  http:
  - match:
    - headers:
        User-Agent:
          regex: .*((iOS)).*
    route:
    - destination:
        host: frontend
        subset: estable
      weight: 60
    - destination:
        host: frontend
        subset: beta
      weight: 40
  - route:
    - destination:
        host: frontend
        subset: estable

5.1.5 Enrutamiento multi-servicio con versiones cruzadas

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-frontend
spec:
  hosts:
  - "*"
  gateways:
  - istio-system/gateway-produccion
  http:
  - match:
    - headers:
        cookie:
          regex: ^(.*?;)?(rol=administrador)(;.*)?$
    route:
    - destination:
        host: frontend
        subset: beta
  - route:
    - destination:
        host: frontend
        subset: estable
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-prevision
spec:
  hosts:
  - prevision
  http:
  - match:
    - sourceLabels:
        version: beta
    route:
    - destination:
        host: prevision
        subset: beta
  - route:
    - destination:
        host: prevision
        subset: estable

5.2 Gobernanza del tráfico

Las reglas de DestinationRule definen cómo se distribuye el tráfico entre las instancias del backend.

5.2.1 Balanceo de carga

Algoritmos simples (round-robin y aleatorio):

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: regla-anuncios
spec:
  host: anuncios
  subsets:
  - labels:
      version: v1
    name: v1
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN  # Alternativas: RANDOM, ROUND_ROBIN

Distribución por topología geográfica:

# Etiquetas en nodos: topology.kubernetes.io/region, topology.kubernetes.io/zone
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: distribucion-anuncios
spec:
  host: anuncios.produccion.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      localityLbSetting:
        enabled: true
        distribute:
        - from: region-sur/zona-sur-1/*
          to:
            "region-sur/zona-sur-1/ciudad-a": 20
            "region-sur/zona-sur-2/ciudad-b": 60
            "region-sur/zona-sur-2/ciudad-c": 20

Conmutación por error:

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: conmutacion-recomendacion
spec:
  host: recomendacion.produccion.svc.cluster.local
  trafficPolicy:
    connectionPool:
      http:
        maxRequestsPerConnection: 1
    loadBalancer:
      simple: ROUND_ROBIN
      localityLbSetting:
        enabled: true
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 1s
      baseEjectionTime: 2m

5.2.2 Persistencia de sesión

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: regla-anuncios
  namespace: produccion
spec:
  host: anuncios
  subsets:
  - labels:
      version: v1
    name: v1
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpCookie:
          name: sesion_usuario
          ttl: 120s

5.2.3 Inyección de fallos

Inyección de retardo:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-anuncios
spec:
  hosts:
  - anuncios
  http:
  - fault:
      delay:
        fixedDelay: 5s
        percentage:
          value: 50
    route:
    - destination:
        host: anuncios
        subset: v1

Inyección de error:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-anuncios
spec:
  hosts:
  - anuncios
  http:
  - fault:
      abort:
        httpStatus: 503
        percentage:
          value: 100
    route:
    - destination:
        host: anuncios
        subset: v1

5.2.4 Tiempos de espera

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-prevision
spec:
  hosts:
  - prevision
  http:
  - route:
    - destination:
        host: prevision
        subset: beta
    timeout: 3s

5.2.5 Reintentos

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-prevision
spec:
  hosts:
  - prevision
  http:
  - route:
    - destination:
        host: prevision
        subset: beta
    retries:
      attempts: 3
      perTryTimeout: 2s
      retryOn: "5xx,reset,connect-failure"

5.2.6 Redirección

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-anuncios
spec:
  hosts:
  - anuncios
  http:
  - match:
    - uri:
        prefix: /publicidad
    redirect:
      uri: /mantenimiento
      authority: anuncios.produccion.svc.cluster.local

5.2.7 Reescritura de URI

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-anuncios
spec:
  hosts:
  - anuncios
  http:
  - match:
    - uri:
        prefix: /prueba/
    rewrite:
      uri: /
    route:
    - destination:
        host: anuncios
        subset: v1

5.2.8 Circuit breaker

Configuración del circuit breaker:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: regla-prevision
spec:
  host: prevision
  subsets:
    - labels:
        version: v1
      name: v1
    - labels:
        version: beta
      name: beta
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 5
      http:
        http1MaxPendingRequests: 10
        maxRequestsPerConnection: 1
    outlierDetection:
      consecutive5xxErrors: 3
      interval: 15s
      baseEjectionTime: 1m
      maxEjectionPercent: 50

Detección de anomalías y exclusión de instancias:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: regla-prevision
spec:
  host: prevision
  subsets:
    - labels:
        version: v1
      name: v1
    - labels:
        version: beta
      name: beta
  trafficPolicy:
    outlierDetection:
      consecutive5xxErrors: 3
      interval: 15s
      baseEjectionTime: 1m
      maxEjectionPercent: 50

5.2.9 Limitación de velocidad

Limitación global (compartida entre todas las instancias):

# ConfigMap con las reglas de limitación
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-limitador
data:
  config.yaml: |
    domain: limitador-anuncios
    descriptors:
      - key: RUTA
        value: "/api/promociones"
        rate_limit:
          unit: minute
          requests_per_unit: 10
      - key: RUTA
        rate_limit:
          unit: minute
          requests_per_unit: 200
# Despliegue de Redis como backend de almacenamiento
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-store
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis-store
  template:
    metadata:
      labels:
        app: redis-store
    spec:
      containers:
      - image: redis:7-alpine
        imagePullPolicy: Always
        name: redis
        ports:
        - containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis-store
spec:
  ports:
  - name: redis
    port: 6379
  selector:
    app: redis-store
# Servicio limitador de velocidad
apiVersion: apps/v1
kind: Deployment
metadata:
  name: limitador
spec:
  replicas: 1
  selector:
    matchLabels:
      app: limitador
  template:
    metadata:
      labels:
        app: limitador
    spec:
      containers:
      - image: registry.example.com/envoyproxy/ratelimit:latest
        imagePullPolicy: Always
        name: limitador
        command: ["/bin/ratelimit"]
        env:
        - name: LOG_LEVEL
          value: debug
        - name: REDIS_SOCKET_TYPE
          value: tcp
        - name: REDIS_URL
          value: redis-store:6379
        - name: USE_STATSD
          value: "false"
        - name: RUNTIME_ROOT
          value: /data
        - name: RUNTIME_SUBDIRECTORY
          value: ratelimit
        ports:
        - containerPort: 8080
        - containerPort: 8081
        volumeMounts:
        - name: vol-config
          mountPath: /data/ratelimit/config/config.yaml
          subPath: config.yaml
      volumes:
      - name: vol-config
        configMap:
          name: config-limitador
---
apiVersion: v1
kind: Service
metadata:
  name: limitador
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  - name: grpc
    port: 8081
    targetPort: 8081
  selector:
    app: limitador
# EnvoyFilter para integrar el limitador global
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: limitador-global
spec:
  workloadSelector:
    labels:
      app: anuncios
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.ratelimit
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
            domain: limitador-anuncios
            failure_mode_deny: true
            rate_limit_service:
              grpc_service:
                envoy_grpc:
                  cluster_name: cluster_limitador
                timeout: 10s
              transport_api_version: V3
    - applyTo: CLUSTER
      match:
        cluster:
          service: limitador.produccion.svc.cluster.local
      patch:
        operation: ADD
        value:
          name: cluster_limitador
          type: STRICT_DNS
          connect_timeout: 10s
          lb_policy: ROUND_ROBIN
          http2_protocol_options: {}
          load_assignment:
            cluster_name: cluster_limitador
            endpoints:
            - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: limitador.produccion.svc.cluster.local
                      port_value: 8081

Limitación local (por instancia individual):

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: limitador-local
spec:
  workloadSelector:
    labels:
      app: anuncios
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.local_ratelimit
          typed_config:
            "@type": type.googleapis.com/udpa.type.v1.TypedStruct
            type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
            value:
              stat_prefix: http_limitador_local
              token_bucket:
                max_tokens: 5
                tokens_per_fill: 5
                fill_interval: 60s
              filter_enabled:
                runtime_key: local_rate_limit_enabled
                default_value:
                  numerator: 100
                  denominator: HUNDRED
              filter_enforced:
                runtime_key: local_rate_limit_enforced
                default_value:
                  numerator: 100
                  denominator: HUNDRED
              response_headers_to_add:
                - append: false
                  header:
                    key: x-limitador-local
                    value: 'true'

5.2.10 Aislamiento de servicios

apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
  name: aislamiento-frontend
spec:
  workloadSelector:
    labels:
      app: frontend
  egress:
  - hosts:
    - "produccion/anuncios.produccion.svc.cluster.local"
    - "istio-system/*"

5.2.11 Espejo de tráfico

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-prevision
spec:
  hosts:
  - prevision
  http:
  - route:
      - destination:
          host: prevision
          subset: v1
        weight: 100
    mirror:
      host: prevision
      subset: beta
    mirrorPercentage:
      value: 50.0

5.3 Exposición de servicios

5.3.1 Publicar servicio HTTPS

# Crear un Secret con los certificados TLS
kubectl create secret tls tls-mi-servicio \
  --cert=certificado.crt --key=clave-privada.key -n produccion

---
# Definir el Gateway
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: gw-mi-servicio
  namespace: produccion
spec:
  selector:
    istio: ingressgateway
  servers:
    - hosts:
        - 'mi-dominio.com'
      port:
        name: https-entrada
        number: 443
        protocol: HTTPS
      tls:
        mode: SIMPLE
        credentialName: tls-mi-servicio

---
# Definir el VirtualService
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-mi-servicio
  namespace: produccion
spec:
  hosts:
  - "mi-dominio.com"
  gateways:
  - produccion/gw-mi-servicio
  http:
  - route:
    - destination:
        host: mi-servicio
        port:
          number: 8080

5.3.2 Exponer servicio HTTP

# Gateway
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gw-tienda
  namespace: ingress
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 9090
      name: http-tienda
      protocol: HTTP
    hosts:
    - "tienda.local"

---
# VirtualService
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-tienda
  namespace: entorno-pruebas
spec:
  hosts:
  - "tienda.local"
  gateways:
  - ingress/gw-tienda
  http:
  - match:
    - port: 9090
    route:
    - destination:
        host: tienda
        port:
          number: 8080
# Agregar el puerto 9090 al servicio del ingress gateway
# Editar el Service istio-ingressgateway para incluir:
ports:
  - name: tienda
    nodePort: 31234
    port: 9090
    protocol: TCP
    targetPort: 9090
# Configurar resolución DNS local
# En /etc/hosts agregar:
# 10.0.0.1 tienda.local
  1. Flujo del tráfico en Istio

Cliente → Ingress Gateway → VirtualService → DestinationRule → Backend
  • Gateway: Define qué tráfico externo puede entrar a la malla. Se conecta con VirtualService.
  • VirtualService: Establece las rutas de enrutamiento. Debe referenciar un servicio real.
  • DestinationRule: Define políticas de ditsribución hacia las instancias del backend (balanceo, TLS, circuit breaker).
  1. Recursos fundamentales

7.1 VirtualService

Configura cómo las solicitudes se enrutan dentro de la malla de servicios hacia destinos específicos.

7.2 DestinationRule

Define políticas de tráfico aplicables después del enrutamiento: balanceo de carga, configuración TLS, circuit breaker.

7.3 Gateway

Selecciona un punto de entrada y el puerto por el cual el tráfico externo ingresa a la malla. El VirtualService debe vincularse explícitamente al Gateway.

7.4 ServiceEntry

Registra servicios externos a la malla para integrarlos en el mecanismo de descubrimiento.

7.5 Sidecar

Configura políticas de aislamiento de red, controlando qué servicios puede alcanzar cada workload.

  1. Seguridad

8.1 Arquitectura de seguridad

El sistema de seguridad de Istio comprende:

  • Una autoridad certificadora (CA)
  • Un servidor API para distribuir certificados, políticas de autenticación, autorización y nombres seguros
  • Un agente sidecar para ejecutar políticas
  • Extensiones del proxy Envoy para auditoría y telemetría

El plano de control proporciona certificados y los proxies sidecar ejecutan las políticas, logrando cifrado de tráfico sin modificar las aplicaciones.

8.2 Conceptos clave

Nombres seguros

La identidad del servidor se codifica en el certificado. El mapeo entre identidad y nombre de servicio determina qué servicio está autorizado a ejecutarse. Nota: en capas inferiores a la 7, la seguridad de nombres no está garantizada ya que la comunicación ocurre por IP antes del proxy.

8.3 Gestión de identidades y certificados

El agente istio-agent (proceso pilot-agent dentro del contenedor sidecar) ejecuta el siguiente flujo:

  1. Istiod expone un servicio gRPC para recibir solicitudes de firma de certificados (CSR).
  2. Al iniciarse, istio-agent genera una clave privada y una CSR, enviándolas a Istiod para firma.
  3. La CA de Istiod valida las credenciales y firma la CSR.
  4. Cuando el workload arranca, Envoy solicita certificados al istio-agent mediante SDS (Secret Discovery Service).
  5. El istio-agent entrega los certificados y claves a Envoy a través de SDS.
  6. El agente vigila la expiración y repite el proceso para renovación automática.

8.4 Autenticación

Las políticas de autenticación tienen alcance jerárquico, desde el workload individual hasta toda la malla.

8.4.1 Autenticación entre pares (mTLS)

Autenticación mutua entre servicios para verificar la identidad del cliente. Utiliza mTLS con versión mínima 1.2.

Flujo de funcionamiento:

  1. Istio redirige el tráfico de salida al sidecar Envoy del cliente.
  2. El Envoy del cliente inicia el handshake TLS mutuo con el Envoy del servidor, verificando además que la cuenta de servicio esté autorizada.
  3. Se establece la conexión cifrada entre ambos proxies.
  4. El Envoy del servidor autoriza la petición y la reenvía al backend.

Despliegue de servicios de prueba:

# Crear namespaces de prueba
kubectl create ns entorno-a entorno-b entorno-legacy
kubectl label ns entorno-a istio-injection=enabled
kubectl label ns entorno-b istio-injection=enabled
kubectl label ns entorno-legacy istio-injection=enabled

# Desplegar servicios de prueba
kubectl apply -f dormir.yaml -n entorno-a
kubectl apply -f dormir.yaml -n entorno-b
kubectl apply -f dormir.yaml -n entorno-legacy
kubectl apply -f httpbin.yaml -n entorno-a
kubectl apply -f httpbin.yaml -n entorno-b
kubectl apply -f httpbin.yaml -n entorno-legacy
# dormir.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dormir
---
apiVersion: v1
kind: Service
metadata:
  name: dormir
  labels:
    app: dormir
spec:
  ports:
  - port: 80
    name: http
  selector:
    app: dormir
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dormir
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dormir
  template:
    metadata:
      labels:
        app: dormir
    spec:
      terminationGracePeriodSeconds: 0
      serviceAccountName: dormir
      containers:
      - name: dormir
        image: registry.example.com/curl:latest
        command: ["/bin/sleep", "infinity"]
        imagePullPolicy: IfNotPresent

Aplicar política de mTLS estricta:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: "politica-mtls-global"
  namespace: "istio-system"
spec:
  mtls:
    mode: STRICT

8.4.2 Autenticación de solicitudes (JWT)

Autenticación de usuarios finales mediante tokens JWT.

Despliegue de prueba:

kubectl create ns entorno-jwt
kubectl label ns entorno-jwt istio-injection=enabled
kubectl apply -f httpbin.yaml -n entorno-jwt
kubectl apply -f httpbin-gateway.yaml
# httpbin-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gw-httpbin
  namespace: ingress
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-httpbin
  namespace: entorno-jwt
spec:
  hosts:
  - "*"
  gateways:
  - ingress/gw-httpbin
  http:
  - route:
    - destination:
        host: httpbin
        port:
          number: 8000

Configurar validación JWT en el gateway:

apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: jwt-ingress
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  jwtRules:
  - issuer: "testing@seguro.istio.io"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.20/security/tools/jwt/samples/jwks.json"

8.5 Autorización

Istio proporciona control de acceso a nivel de malla, namespace y workload. Soporta políticas ALLOW y DENY con semántica flexible basada en atributos del sistema.

Componentes de una política de autorización:

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: politica-httpbin
  namespace: entorno-jwt
spec:
  selector:
    matchLabels:
      app: httpbin
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/dormir"]
    to:
    - operation:
        methods: ["GET"]
    when:
    - key: request.auth.claims[iss]
      values: ["https://accounts.google.com"]

8.5.1 Control de acceso en capa 7

# Permitir solo peticiones GET
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: solo-lectura-tienda
  namespace: default
spec:
  selector:
    matchLabels:
      app: tienda
  action: ALLOW
  rules:
  - to:
    - operation:
        methods: ["GET"]

---
# Autorización por cuenta de servicio
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: catalogo-autorizado
  namespace: default
spec:
  selector:
    matchLabels:
      app: catalogo
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/sa-tienda"]
    to:
    - operation:
        methods: ["GET"]

8.5.2 Control de acceso en capa 4

# Permitir tráfico TCP en puertos específicos
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: politica-tcp
  namespace: entorno-pruebas
spec:
  selector:
    matchLabels:
      app: echo-tcp
  action: ALLOW
  rules:
  - to:
    - operation:
        ports: ["9000", "9001"]

---
# Denegar tráfico HTTP
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: denegar-http
  namespace: entorno-pruebas
spec:
  selector:
    matchLabels:
      app: echo-tcp
  action: DENY
  rules:
  - to:
    - operation:
        methods: ["GET"]

8.5.3 Control de acceso en el gateway

# Restringir acceso por IP de origen
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: politica-ingress
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: ALLOW
  rules:
  - from:
    - source:
        ipBlocks: ["192.168.1.0/24", "10.0.0.5"]
  1. Registro de servicios externos

Istio permite incorporar servicios que se ejecutan fuera de Kubernetes, como aplicaciones en máquinas virtuales.

9.1 Conceptos

  • WorkloadGroup: Define un conjunto lógico de workloads de VM con atributos comunes. Equivalente a un Deployment en Kubernetes.
  • WorkloadEntry: Representa una instancia individual de un workload de VM. Equivalente a un Pod.

9.2 Proceso de integración

9.2.1 Variables necesarias

NOMBRE_APP="mi-app-vm"
NAMESPACE_VM="mi-namespace"
DIR_TRABAJO="/ruta/certificados"
CUENTA_SERVICIO="sa-vm"
RED_CLUSTER=""
RED_VM=""
CLUSTER="kubernetes-principal"

9.2.2 Configuración del operador Istio

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio-vm
spec:
  values:
    global:
      meshID: malla1
      multiCluster:
        clusterName: kubernetes-principal
      network: 10.200.0.0/16

9.2.3 Despliegue del gateway este-oeste

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: gateway-este-oeste
spec:
  profile: empty
  components:
    ingressGateways:
      - name: istio-eastwestgateway
        label:
          istio: eastwestgateway
          app: istio-eastwestgateway
        enabled: true
        k8s:
          service:
            ports:
              - name: status-port
                port: 15021
                targetPort: 15021
              - name: tls
                port: 15443
                targetPort: 15443
              - name: tls-istiod
                port: 15012
                targetPort: 15012
              - name: tls-webhook
                port: 15017
                targetPort: 15017
  values:
    gateways:
      istio-ingressgateway:
        injectionTemplate: gateway

9.2.4 Gateway y VirtualService para Istiod

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gw-istiod
spec:
  selector:
    istio: eastwestgateway
  servers:
    - port:
        name: tls-istiod
        number: 15012
        protocol: tls
      tls:
        mode: PASSTHROUGH
      hosts:
        - "*"
    - port:
        name: tls-webhook
        number: 15017
        protocol: tls
      tls:
        mode: PASSTHROUGH
      hosts:
        - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-istiod
spec:
  hosts:
  - "*"
  gateways:
  - gw-istiod
  tls:
  - match:
    - port: 15012
      sniHosts:
      - "*"
    route:
    - destination:
        host: istiod.istio-system.svc.cluster.local
        port:
          number: 15012
  - match:
    - port: 15017
      sniHosts:
      - "*"
    route:
    - destination:
        host: istiod.istio-system.svc.cluster.local
        port:
          number: 443

9.2.5 Cuenta de servicio y permisos

apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-nginx-vm
  namespace: vm
---
apiVersion: v1
kind: Secret
metadata:
  name: secreto-sa-nginx
  namespace: vm
  annotations:
    kubernetes.io/service-account.name: sa-nginx-vm
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: binding-vm
subjects:
- kind: ServiceAccount
  name: sa-nginx-vm
  namespace: vm
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: istiod-istio-system
  apiGroup: rbac.authorization.k8s.io

9.2.6 WorkloadGroup y archivos de configuración

apiVersion: networking.istio.io/v1alpha3
kind: WorkloadGroup
metadata:
  name: nginx-vm
  namespace: vm
spec:
  metadata:
    labels:
      app: nginx-vm
  template:
    serviceAccount: sa-nginx-vm
  probe:
    httpGet:
      port: 80
# Generar archivos de configuración para la VM
istioctl x workload entry configure \
  -f workloadgroup.yaml \
  -o "${DIR_TRABAJO}" \
  --clusterID "${CLUSTER}" \
  --ingressIP=10.0.1.100

# Archivos generados:
# cluster.env  - Metadatos del namespace y red
# istio-token  - Token para obtener certificados
# mesh.yaml    - Configuración del proxy
# root-cert.pem - Certificado raíz
# hosts        - Entradas adicionales para /etc/hosts

9.2.7 Configuración de la máquina virtual

# Instalar certificado raíz
sudo mkdir -p /etc/certs
sudo cp root-cert.pem /etc/certs/root-cert.pem

# Instalar token
sudo mkdir -p /var/run/secrets/tokens
sudo cp istio-token /var/run/secrets/tokens/istio-token

# Instalar el paquete sidecar (Debian)
curl -LO https://storage.googleapis.com/istio-release/releases/1.18.2/deb/istio-sidecar.deb
sudo dpkg -i istio-sidecar.deb

# Para CentOS:
# curl -LO https://storage.googleapis.com/istio-release/releases/1.18.2/rpm/istio-sidecar.rpm
# sudo rpm -i istio-sidecar.rpm

# Copiar configuración
sudo cp cluster.env /var/lib/istio/envoy/cluster.env
sudo cp mesh.yaml /etc/istio/config/mesh

# Actualizar /etc/hosts
sudo sh -c 'cat hosts >> /etc/hosts'

# Asignar permisos al proxy
sudo mkdir -p /etc/istio/proxy
sudo chown -R istio-proxy \
  /var/lib/istio \
  /etc/certs \
  /etc/istio/proxy \
  /etc/istio/config \
  /var/run/secrets

9.2.8 Iniciar el servicio en la VM

sudo systemctl start istio
# Verificar logs
tail -f /var/log/istio/istio.log

9.3 ServiceEntry

Registra servicios externos para integrarlos en el mecanismo de descubrimiento de Istio, tratándolos como si fueran servicios nativos de la malla.

9.4 WorkloadGroup

Sirve como plantilla para el registro automático de instancias de VM. Equivalente al Deployment de Kubernetes.

9.5 WorkloadEntry

Representa y registra instancias individuales de servicios que se ejecutan fuera de Kubernetes.

Etiquetas: Istio service-mesh envoy Kubernetes traffic-management

Publicado el 7-11 18:12