Istio ServiceEntry explicado: servicios externos, DNS y control de tráfico
Todo clúster Kubernetes en producción se comunica con el exterior. Tus servicios llaman a APIs de pago, se conectan a bases de datos gestionadas, envían eventos a plataformas SaaS y contactan con sistemas legacy que nunca van a correr dentro del mesh. Por defecto, Istio permite que todo el tráfico de salida fluya libremente, o bien lo bloquea completamente si configuras outboundTrafficPolicy a REGISTRY_ONLY. Ninguno de los dos extremos te da lo que realmente necesitas: acceso selectivo, observable y controlado por políticas a los servicios externos.
Eso es exactamente lo que resuelve Istio ServiceEntry. Registra endpoints externos en el registro interno del mesh para que los sidecars de Envoy puedan aplicar las mismas capacidades de gestión de tráfico, seguridad y observabilidad a las llamadas salientes que ya disfrutas para el tráfico east-west. Sin proxies adicionales, sin egress gateways para el caso básico: solo un recurso YAML que le dice al mesh «este servicio externo existe, y así es como llegar a él».
En esta guía recorro todos los campos del spec de ServiceEntry, explico los cuatro modos de resolución DNS con casos de uso reales, y muestro patrones listos para producción con APIs externas, bases de datos, servicios TCP y cargas de trabajo legacy. También cubrimos cómo combinar ServiceEntry con DestinationRule y VirtualService para obtener circuit breaking, reintentos, connection pooling e incluso sticky sessions para dependencias externas.
Qué es un ServiceEntry
Istio mantiene un registro interno de servicios que fusiona los Kubernetes Services con cualquier entrada adicional que declares. Cuando un sidecar proxy necesita decidir cómo enrutar una petición, consulta ese registro. Los servicios dentro del mesh se registran automáticamente. Los servicios fuera del mesh no lo hacen, a menos que crees un ServiceEntry.
Un ServiceEntry es un recurso personalizado que añade una entrada al registro de servicios del mesh. Una vez registrado, el servicio externo se convierte en un ciudadano de primera clase: Envoy genera clusters, routes y listeners para él, lo que significa que obtienes métricas (istio_requests_total), access logs, trazas distribuidas, originación mTLS, reintentos, timeouts y circuit breaking. El conjunto completo de funcionalidades de Istio.
Sin un ServiceEntry, el tráfico de salida hacia un host externo pasa como una conexión TCP en bruto (en modo ALLOW_ANY) sin telemetría alguna, o se descarta con un 502/503 (en modo REGISTRY_ONLY). Ambos resultados son indeseables en producción. El ServiceEntry cierra esa brecha.
Anatomía de ServiceEntry: todos los campos explicados
Veamos un ServiceEntry completo y desglosemos cada campo.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-api
namespace: production
spec:
hosts:
- api.stripe.com
location: MESH_EXTERNAL
ports:
- number: 443
name: https
protocol: TLS
resolution: DNS
exportTo:
- "."
- "istio-system"
hosts
Lista de hostnames asociados al servicio. Para servicios externos, suele ser el nombre DNS que utiliza tu aplicación (p. ej., api.stripe.com). Para servicios con protocolos HTTP, el campo hosts se compara con la cabecera HTTP Host. Para protocolos no HTTP o servicios sin nombre DNS, puedes usar un hostname sintético y combinarlo con addresses o endpoints estáticos.
addresses
Direcciones IP virtuales opcionales asociadas al servicio. Son útiles para servicios TCP en los que quieres asignar una VIP que el sidecar interceptará. No son necesarias para servicios HTTP/HTTPS que usan enrutamiento basado en hostname.
ports
Los puertos en los que el servicio externo está expuesto. Cada puerto requiere number, name y protocol. El protocolo importa: configurarlo como TLS le dice a Envoy que haga enrutamiento basado en SNI sin terminar TLS. Configurarlo como HTTPS implica HTTP sobre TLS. Para bases de datos, usarás típicamente TCP.
location
MESH_EXTERNAL o MESH_INTERNAL. Usa MESH_EXTERNAL para servicios fuera de tu clúster (APIs de terceros, bases de datos gestionadas). Usa MESH_INTERNAL para servicios dentro de tu infraestructura que no forman parte del mesh: por ejemplo, VMs corriendo en el mismo VPC que no tienen sidecar, o un Kubernetes Service en un namespace sin inyección de sidecar habilitada. La location afecta a cómo se aplica mTLS y cómo se etiquetan las métricas.
resolution
Determina cómo el sidecar resuelve las direcciones de los endpoints. Es el campo más crítico y le dedico la siguiente sección en su totalidad. Opciones: NONE, STATIC, DNS, DNS_ROUND_ROBIN.
endpoints
Lista explícita de endpoints de red. Obligatorio cuando resolution es STATIC. Opcional con resolución DNS para proporcionar labels o información de localidad. Cada endpoint puede tener address, ports, labels, network, locality y weight.
exportTo
Controla la visibilidad de este ServiceEntry entre namespaces. Usa "." para el namespace actual únicamente, "*" para todos los namespaces. En clústeres multi-equipo, restringe los exports para evitar la contaminación de namespaces.
Modos de resolución DNS: NONE vs STATIC vs DNS vs DNS_ROUND_ROBIN
El campo resolution determina cómo Envoy descubre las direcciones IP detrás del servicio. Equivocarse con este campo es la causa número uno de errores de configuración en ServiceEntry. A continuación, una explicación clara.
| Resolución | Funcionamiento | Mejor para |
|---|---|---|
NONE | Envoy usa la IP de destino original de la conexión. Sin consulta DNS por parte del proxy. | Entradas wildcard, escenarios pass-through, servicios donde la aplicación ya resolvió la IP. |
STATIC | Envoy enruta a las IPs listadas en el campo endpoints. Sin DNS. | Servicios con IPs estables y conocidas (p. ej., bases de datos on-prem, VMs con IPs fijas). |
DNS | Envoy resuelve el hostname en el momento de la conexión y crea un endpoint por IP devuelta. Usa DNS asíncrono con health checking por IP. | APIs externas detrás de load balancers, bases de datos gestionadas con endpoints DNS (RDS, CloudSQL). |
DNS_ROUND_ROBIN | Envoy resuelve el hostname y usa un único endpoint lógico, rotando entre las IPs devueltas. Sin health checking por IP. | Servicios externos simples, servicios donde no necesitas circuit breaking por endpoint. |
Cuándo usar NONE
Usa NONE cuando quieras registrar un rango de IPs externas o hosts wildcard sin que Envoy realice ninguna resolución de direcciones. Esto es habitual para políticas de egress amplias: «permitir tráfico a *.googleapis.com en el puerto 443». Envoy simplemente reenvía el tráfico a la IP que la aplicación resolvió via kube-dns. El inconveniente: Envoy tiene capacidad limitada para aplicar políticas por endpoint.
Cuándo usar STATIC
Usa STATIC cuando el servicio externo tiene direcciones IP conocidas y estables que raramente cambian. Esto evita dependencias DNS por completo. Defines las IPs en la lista de endpoints. Caso de uso clásico: una base de datos Oracle legacy en una IP fija en tu centro de datos.
Cuándo usar DNS
Usa DNS para la mayoría de integraciones con APIs externas. Envoy realiza resolución DNS asíncrona y crea un endpoint en el cluster para cada IP devuelta. Esto habilita health checking y circuit breaking por endpoint, algo crítico para la fiabilidad en producción. Este es el modo que quieres para servicios como api.stripe.com o el endpoint de tu instancia RDS.
Cuándo usar DNS_ROUND_ROBIN
Usa DNS_ROUND_ROBIN cuando el hostname externo devuelve muchas IPs y no necesitas circuit breaking por IP. Envoy trata todas las IPs resueltas como un único endpoint lógico y hace round-robin entre ellas. Es más ligero que el modo DNS y evita crear un número elevado de endpoints en la configuración de clusters de Envoy.
Patrones prácticos
Patrón 1: API HTTP externa (api.stripe.com)
El patrón de ServiceEntry más habitual. Tu aplicación llama a una API HTTPS de terceros. Quieres telemetría de Istio y, opcionalmente, reintentos y timeouts.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: stripe-api
namespace: payments
spec:
hosts:
- api.stripe.com
location: MESH_EXTERNAL
ports:
- number: 443
name: tls
protocol: TLS
resolution: DNS
El protocolo es TLS, no HTTPS. Como tu aplicación inicia el handshake TLS directamente, Envoy gestiona esto como TLS opaco mediante enrutamiento basado en SNI. Si estuvieras terminando TLS en el sidecar y haciendo originación TLS via un DestinationRule, configurarías el protocolo como HTTP y gestionarías el upgrade por separado. Pero para la mayoría de APIs externas, deja que la aplicación gestione su propio TLS.
Patrón 2: Base de datos gestionada externa (RDS / CloudSQL)
Las bases de datos gestionadas exponen un endpoint DNS que resuelve a una o varias IPs. Durante un failover, el registro DNS cambia. Necesitas que Envoy respete los TTLs DNS y enrute al primary actual.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: orders-database
namespace: orders
spec:
hosts:
- orders-db.abc123.us-east-1.rds.amazonaws.com
location: MESH_EXTERNAL
ports:
- number: 5432
name: postgres
protocol: TCP
resolution: DNS
Para servicios TCP, Envoy no puede usar cabeceras HTTP para enrutar, por lo que depende de coincidencia basada en IP. El modo de resolución DNS garantiza que Envoy resuelva periódicamente el hostname y actualice su lista de endpoints. Esto es crítico para escenarios de failover RDS Multi-AZ, donde el endpoint DNS apunta a una nueva IP.
Patrón 3: Servicio interno legacy no incluido en el mesh
Tienes un servicio de monitorización corriendo en un conjunto de VMs con IPs conocidas dentro de tu VPC. No forma parte del mesh, pero tus servicios dentro del mesh necesitan comunicarse con él.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: legacy-monitoring
namespace: observability
spec:
hosts:
- legacy-monitoring.internal
location: MESH_INTERNAL
ports:
- number: 8080
name: http
protocol: HTTP
resolution: STATIC
endpoints:
- address: 10.0.5.10
- address: 10.0.5.11
- address: 10.0.5.12
Diferencias clave: location es MESH_INTERNAL porque el servicio vive dentro de tu red, y resolution es STATIC porque conocemos las IPs. El hostname legacy-monitoring.internal es sintético: tu aplicación lo usa, y el DNS proxy de Istio (o una entrada de CoreDNS) lo resuelve a uno de los endpoints listados.
Patrón 4: Servicios TCP con múltiples puertos
Algunos servicios externos exponen múltiples puertos TCP: por ejemplo, un clúster Elasticsearch con puertos de datos (9200) y de transporte (9300).
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-elasticsearch
namespace: search
spec:
hosts:
- es.example.com
location: MESH_EXTERNAL
ports:
- number: 9200
name: http
protocol: HTTP
- number: 9300
name: transport
protocol: TCP
resolution: DNS
Cada puerto obtiene su propia configuración de listener en Envoy. El puerto HTTP se beneficia de telemetría completa de capa 7 y gestión de tráfico. El puerto TCP obtiene métricas de capa 4 y políticas a nivel de conexión.
Combinando ServiceEntry con DestinationRule
Un ServiceEntry por sí solo registra el servicio externo. Para aplicar políticas de tráfico —connection pooling, circuit breaking, originación TLS, load balancing— lo combinas con un DestinationRule. Aquí es donde la cosa se pone interesante.
Connection pooling y circuit breaking
Las APIs externas tienen rate limits. Tu base de datos gestionada tiene un número máximo de conexiones. Proteger estas dependencias a nivel del mesh previene fallos en cascada.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: stripe-api
namespace: payments
spec:
hosts:
- api.stripe.com
location: MESH_EXTERNAL
ports:
- number: 443
name: tls
protocol: TLS
resolution: DNS
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: stripe-api-dr
namespace: payments
spec:
host: api.stripe.com
trafficPolicy:
connectionPool:
tcp:
maxConnections: 50
connectTimeout: 5s
http:
h2UpgradePolicy: DO_NOT_UPGRADE
maxRequestsPerConnection: 100
outlierDetection:
consecutive5xxErrors: 3
interval: 30s
baseEjectionTime: 60s
maxEjectionPercent: 100
Esta configuración limita las conexiones de salida a Stripe a 50, establece un timeout de conexión de 5 segundos y expulsa los endpoints que devuelvan 3 errores 5xx consecutivos. En producción, esto evita que una API de terceros degradada consuma todos tus slots de conexión y provoque un efecto dominó en tus servicios.
Originación TLS
A veces tu aplicación habla HTTP en claro, pero el servicio externo requiere HTTPS. En lugar de modificar el código de la aplicación, puedes delegar la originación TLS al sidecar.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-api
namespace: default
spec:
hosts:
- api.external-service.com
location: MESH_EXTERNAL
ports:
- number: 80
name: http
protocol: HTTP
- number: 443
name: https
protocol: TLS
resolution: DNS
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: external-api-tls
namespace: default
spec:
host: api.external-service.com
trafficPolicy:
portLevelSettings:
- port:
number: 443
tls:
mode: SIMPLE
Tu aplicación envía HTTP al puerto 80. Un VirtualService (que se muestra en la siguiente sección) redirige eso al puerto 443. El DestinationRule inicia TLS hacia el endpoint externo. La aplicación nunca sabe que TLS ocurrió.
Combinando ServiceEntry con VirtualService
VirtualService te da gestión de tráfico de capa 7 para servicios externos: reintentos, timeouts, inyección de fallos, enrutamiento basado en cabeceras y traffic shifting. Esto es invaluable cuando migras entre proveedores de API o necesitas políticas de resiliencia para dependencias externas poco fiables.
Reintentos y timeouts
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: stripe-api-vs
namespace: payments
spec:
hosts:
- api.stripe.com
http:
- route:
- destination:
host: api.stripe.com
port:
number: 443
timeout: 10s
retries:
attempts: 3
perTryTimeout: 3s
retryOn: connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes
retryRemoteLocalities: true
Esto aplica un timeout global de 10 segundos con hasta 3 intentos de reintento (3 segundos cada uno) para condiciones de fallo específicas. Ten en cuenta que esto solo funciona para ServiceEntries con protocolo HTTP. Para entradas con protocolo TLS, donde Envoy no puede ver la capa HTTP, estás limitado a reintentos de conexión TCP configurados via DestinationRule.
Traffic shifting entre proveedores externos
¿Migrando de una API externa a otra? Usa weighted routing para desplazar el tráfico de forma gradual.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: geocoding-primary
namespace: geo
spec:
hosts:
- geocoding.internal
location: MESH_EXTERNAL
ports:
- number: 443
name: tls
protocol: TLS
resolution: STATIC
endpoints:
- address: api.old-geocoding-provider.com
labels:
provider: old
- address: api.new-geocoding-provider.com
labels:
provider: new
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: geocoding-dr
namespace: geo
spec:
host: geocoding.internal
trafficPolicy:
tls:
mode: SIMPLE
subsets:
- name: old-provider
labels:
provider: old
- name: new-provider
labels:
provider: new
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: geocoding-vs
namespace: geo
spec:
hosts:
- geocoding.internal
http:
- route:
- destination:
host: geocoding.internal
subset: old-provider
weight: 80
- destination:
host: geocoding.internal
subset: new-provider
weight: 20
Esto envía el 80% del tráfico de geocodificación al proveedor antiguo y el 20% al nuevo. Ajusta los pesos a medida que ganas confianza. Completamente reversible: basta con devolver el proveedor antiguo al 100%.
Patrones de resolución DNS: Istio DNS Proxy vs kube-dns
La resolución DNS de Istio para servicios externos implica dos capas: cómo tu aplicación resuelve el hostname (kube-dns / CoreDNS) y cómo el sidecar resuelve el hostname (DNS asíncrono de Envoy o el DNS proxy de Istio). Entender la interacción entre ambas capas es crucial para un comportamiento DNS fiable en Istio.
Flujo por defecto (sin Istio DNS Proxy)
Tu aplicación llama a api.stripe.com. kube-dns lo resuelve a una IP. La aplicación abre una conexión a esa IP. El sidecar intercepta la conexión y —si el ServiceEntry usa resolución DNS— Envoy resuelve api.stripe.com de forma independiente para determinar su lista de endpoints. Se producen dos consultas DNS separadas, lo que puede generar inconsistencias si los registros DNS cambian entre ambas resoluciones.
Con el DNS Proxy de Istio (dns.istio.io)
El sidecar de Istio incluye un DNS proxy que intercepta las consultas DNS de la aplicación. Cuando está habilitado (mediante meshConfig.defaultConfig.proxyMetadata.ISTIO_META_DNS_CAPTURE e ISTIO_META_DNS_AUTO_ALLOCATE), el proxy puede:
- Auto-asignar IPs virtuales para hosts de ServiceEntry que no tienen
addressesdefinidas, lo cual es crítico para ServiceEntries TCP que necesitan coincidencia basada en IP. - Resolver hosts de ServiceEntry directamente, evitando el viaje de ida y vuelta a kube-dns para servicios conocidos del mesh.
- Garantizar consistencia entre la resolución DNS de la aplicación y la resolución de endpoints del sidecar.
En instalaciones modernas de Istio (1.18+), la captura DNS está habilitada por defecto. Verifica con:
istioctl proxy-config bootstrap <pod-name> -n <namespace> | grep -A2 "ISTIO_META_DNS"
Cuándo importa más el DNS Proxy
El DNS proxy es especialmente importante para ServiceEntries TCP sin un campo addresses explícito. Sin una VIP, Envoy no puede asociar una conexión TCP entrante al ServiceEntry correcto porque no hay una cabecera HTTP Host que inspeccionar. El DNS proxy resuelve esto auto-asignando una VIP del rango 240.240.0.0/16 y devolviéndola cuando la aplicación resuelve el hostname. El sidecar entonces intercepta el tráfico a esa VIP y lo enruta al endpoint externo correcto.
Sticky sessions con ServiceEntry
Algunos servicios externos requieren afinidad de sesión: por ejemplo, un servicio legacy que almacena el estado de sesión en memoria, o un endpoint WebSocket que debe mantener una conexión persistente al mismo backend. Istio soporta sticky sessions para servicios externos a través de consistent hashing en un DestinationRule.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: legacy-session-service
namespace: default
spec:
hosts:
- legacy-session.internal
location: MESH_INTERNAL
ports:
- number: 8080
name: http
protocol: HTTP
resolution: STATIC
endpoints:
- address: 10.0.1.10
- address: 10.0.1.11
- address: 10.0.1.12
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: legacy-session-dr
namespace: default
spec:
host: legacy-session.internal
trafficPolicy:
loadBalancer:
consistentHash:
httpCookie:
name: SERVERID
ttl: 3600s
Esta configuración hace hash sobre una cookie HTTP llamada SERVERID. Si la cookie no existe, Envoy genera una y la establece en la respuesta para que las peticiones posteriores del mismo cliente vayan al mismo endpoint.
También puedes hacer hash sobre:
- Cabecera HTTP:
consistentHash.httpHeaderName: "x-user-id"— útil cuando tu aplicación envía un identificador de usuario en cada petición. - IP de origen:
consistentHash.useSourceIp: true— opción más sencilla, pero se rompe en entornos con NAT o IPs de egress compartidas. - Parámetro de query:
consistentHash.httpQueryParameterName: "session_id"— para REST APIs que incluyen un identificador de sesión en la URL.
Las sticky sessions con ServiceEntry funcionan de forma idéntica a las sticky sessions dentro del mesh. El requisito clave es que el ServiceEntry debe usar resolución STATIC o DNS (no NONE) para que Envoy tenga múltiples endpoints entre los que aplicar el hash. Con DNS_ROUND_ROBIN, solo hay un endpoint lógico, por lo que el consistent hashing no tiene efecto.
Resolución de problemas comunes
Errores 503 al llamar a servicios externos
El problema más habitual con ServiceEntry. Empieza con esta secuencia de diagnóstico:
# Comprueba si el ServiceEntry está aplicado y visible para el proxy
istioctl proxy-config cluster <pod-name> -n <namespace> | grep <external-host>
# Comprueba los listeners
istioctl proxy-config listener <pod-name> -n <namespace> --port <port>
# Revisa los access logs de Envoy para la petición específica
kubectl logs <pod-name> -n <namespace> -c istio-proxy | grep <external-host>
Causas habituales de errores 503:
- Protocolo incorrecto: establecer
protocol: HTTPScuando tu aplicación inicia TLS. UsaTLSpara pass-through; usaHTTPsolo si el sidecar hace la originación TLS. - ServiceEntry ausente en modo REGISTRY_ONLY: si
outboundTrafficPolicyesREGISTRY_ONLY, cualquier host sin ServiceEntry queda bloqueado. - Restricción de exportTo: el ServiceEntry está en el namespace A, exportado solo a
".", y el pod que llama está en el namespace B. - Fallo de resolución DNS: Envoy no puede resolver el hostname. Comprueba que los servidores DNS sean accesibles desde el pod.
Fallos de resolución DNS
Cuando el resolvedor DNS asíncrono de Envoy falla, verás flags UH (upstream unhealthy) o UF (upstream connection failure) en los access logs.
# Verifica que DNS funciona desde dentro del sidecar
kubectl exec <pod-name> -n <namespace> -c istio-proxy -- \
pilot-agent request GET /dns_resolve?proxyID=<pod-name>.<namespace>&host=api.stripe.com
# Comprueba el estado del cluster Envoy
istioctl proxy-config endpoint <pod-name> -n <namespace> | grep <external-host>
Si el endpoint aparece como UNHEALTHY, Envoy resolvió DNS pero la detección de anomalías expulsó el host. Si no aparece ningún endpoint, la resolución DNS está fallando. Solución habitual: asegúrate de que tus pods pueden llegar a un servidor DNS externo, o que CoreDNS está configurado para reenviar consultas del dominio externo.
La originación TLS no funciona
Si configuraste originación TLS via un DestinationRule pero el tráfico sigue fallando:
- Asegúrate de que el protocolo del puerto en el ServiceEntry es
HTTP, noTLS. Si lo estableces comoTLS, Envoy trata la conexión como TLS opaco pass-through y no aplicará la configuración TLS del DestinationRule. - Verifica que el campo
hostdel DestinationRule coincide exactamente con la entradahostsdel ServiceEntry. - Comprueba que el VirtualService (si se usa) enruta al número de puerto correcto.
El ServiceEntry TCP no intercepta tráfico
Para ServiceEntries con protocolo TCP sin el DNS proxy, Envoy no puede asociar el tráfico por hostname. Debes hacer una de estas cosas:
- Establecer un campo
addressesexplícito con una VIP a la que tu aplicación se dirija. - Habilitar el DNS proxy de Istio para que auto-asigne VIPs.
- Asegurarte de que la IP de destino coincide con lo que resuelve el ServiceEntry.
Sin una de estas opciones, el tráfico TCP pasa por el PassthroughCluster y evita tu ServiceEntry por completo.
Preguntas frecuentes
¿Necesito un ServiceEntry si outboundTrafficPolicy está en ALLOW_ANY?
No lo necesitas para la conectividad: tus servicios pueden alcanzar hosts externos sin él. Pero deberías crearlo de todos modos. Sin ServiceEntry, el tráfico de salida pasa por el PassthroughCluster, lo que significa: sin métricas detalladas por destino, sin access logging con el hostname externo, sin circuit breaking, sin reintentos ni políticas de timeout. Un ServiceEntry es la diferencia entre «funciona» y «funciona de forma fiable con observabilidad».
¿Cuál es la diferencia entre protocol TLS y HTTPS en un puerto de ServiceEntry?
TLS le dice a Envoy que trate la conexión como TLS opaco. Envoy lee la cabecera SNI para determinar el enrutamiento, pero no descifra el payload. Úsalo cuando tu aplicación inicia TLS directamente. HTTPS le dice a Envoy que el protocolo es HTTP sobre TLS, lo que implica que Envoy debe gestionar TLS. En la práctica, para servicios externos donde la aplicación gestiona su propio TLS, usa TLS. Usa HTTP con originación TLS en un DestinationRule cuando quieras que el sidecar gestione TLS.
¿Puedo usar wildcards en los hosts de ServiceEntry?
Sí, pero con limitaciones. Puedes usar *.example.com para coincidir con cualquier subdominio de example.com. Sin embargo, las entradas wildcard solo funcionan con resolution: NONE porque Envoy no puede hacer consultas DNS para hostnames wildcard. Esto significa que pierdes la capacidad de aplicar políticas de tráfico por endpoint. Los ServiceEntries wildcard son más adecuados para control de acceso de egress amplio que para gestión de tráfico granular.
¿Cómo configuro sticky sessions para un servicio externo detrás de un ServiceEntry?
Crea un ServiceEntry con resolución STATIC o DNS (para que Envoy tenga múltiples endpoints) y combínalo con un DestinationRule que configure consistentHash bajo trafficPolicy.loadBalancer. Puedes hacer hash sobre una cookie HTTP, una cabecera, la IP de origen o un parámetro de query. El ServiceEntry debe exponer múltiples endpoints para que el consistent hashing tenga algún efecto. Consulta la sección «Sticky sessions con ServiceEntry» más arriba para un ejemplo YAML completo.
¿Cómo interactúa ServiceEntry con NetworkPolicy y Istio AuthorizationPolicy?
Un ServiceEntry no evita las Kubernetes NetworkPolicy. Si una NetworkPolicy bloquea el egress a la IP externa, el tráfico se descartará a nivel CNI antes de que Envoy pueda enrutarlo. Istio AuthorizationPolicy también puede restringir qué workloads tienen permitido llamar a hosts específicos de ServiceEntry. Para una defensa en profundidad: usa ServiceEntry para la gestión de tráfico y la observabilidad, AuthorizationPolicy para el control de acceso a nivel de workload y NetworkPolicy para la aplicación a nivel de red.
Conclusión
ServiceEntry es uno de los recursos de Istio más prácticos que usarás en producción. Transforma conexiones de salida opacas en tráfico gestionado, observable y controlado por políticas, y lo hace sin requerir cambios en el código de tu aplicación.
Empieza con lo básico: crea un ServiceEntry para cada dependencia externa, establece el tipo de resolución correcto y combínalo con un DestinationRule para límites de conexión y circuit breaking. A medida que madures, añade VirtualServices para reintentos y timeouts, configura sticky sessions donde sea necesario y habilita el DNS proxy para una integración perfecta de servicios TCP.
El patrón es siempre el mismo: registra el servicio, aplica políticas, observa el tráfico. Cada dependencia externa que formalices con un ServiceEntry es un punto ciego menos en tu mesh de producción.