Skip to main content

Documentation Index

Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt

Use this file to discover all available pages before exploring further.

This lesson demonstrates how to control external egress traffic in Istio using ServiceEntry resources and (optionally) an Istio egress Gateway. You’ll learn how to:
  • Install Istio with a demo profile configured to REGISTRY_ONLY outbound policy so only hosts registered in Istio are reachable.
  • Run a test pod and observe how an Envoy sidecar enforces egress restrictions.
  • Create a ServiceEntry to allow www.wikipedia.org.
  • Configure an egress Gateway, DestinationRule, and VirtualService to force traffic through the egress gateway and understand why the mesh gateway entry is required.
Note: Istio routing and egress control apply only to namespaces with sidecar injection enabled.
Label any namespaces that should be managed by Istio (for example: kubectl label namespace default istio-injection=enabled) and recreate pods so the Envoy sidecar can be injected.

Prerequisites

  • A Kubernetes cluster (minikube, Kind, or cloud).
  • curl and kubectl configured to talk to the cluster.
  • istioctl (we use Istio 1.18.2 in examples below).
Refer to the Istio docs for platform-specific setup: Istio documentation.

1. Install istioctl and prepare a demo profile

Download Istio and add istioctl to your PATH:
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.18.2 sh -
cd istio-1.18.2
export PATH=$PWD/bin:$PATH
which istioctl
# /root/istio-1.18.2/bin/istioctl
Dump the demo profile into a YAML file for editing:
istioctl profile dump demo -o yaml > demo.yaml
vim demo.yaml
Find the meshConfig section and set the outbound traffic policy to REGISTRY_ONLY so the mesh only allows egress to hosts known to Istio (via ServiceEntry):
meshConfig:
  outboundTrafficPolicy:
    mode: REGISTRY_ONLY
  accessLogFile: /dev/stdout
  defaultConfig:
    proxyMetadata: {}
Validate and install the customized profile:
istioctl validate -f demo.yaml
istioctl install -f demo.yaml -y
# ✓ Istio core installed
# ✓ Istiod installed
# ✓ Egress gateways installed
# ✓ Ingress gateways installed
# ✓ Installation complete
Verify Istio system pods are running:
kubectl get pods -n istio-system
# NAME                                           READY   STATUS    RESTARTS   AGE
# istio-egressgateway-...                        1/1     Running   0          28s
# istio-ingressgateway-...                       1/1     Running   0          28s
# istiod-...                                     1/1     Running   0          36s

2. Create a test pod and observe default egress behavior

Run a simple test pod with curl installed:
kubectl run test --image=curlimages/curl:8.1.2 --restart=Never --command -- sleep 3600
kubectl exec -ti test -- /bin/sh
From inside the pod, curl Wikipedia to verify normal internet access (no sidecar injected yet):
curl --head -L http://www.wikipedia.org
Example (truncated) response headers:
HTTP/1.1 301 Moved Permanently
location: https://www.wikipedia.org/

HTTP/2 200
content-type: text/html
...
At this stage the pod runs without an Envoy sidecar (namespace not labeled), so it reaches the internet normally.

3. Enable sidecar injection and observe REGISTRY_ONLY effect

Label the namespace for automatic sidecar injection (using the default namespace in this guide), restart the pod, and confirm the sidecar is injected:
kubectl label namespace default istio-injection=enabled
kubectl delete pod test
kubectl run test --image=curlimages/curl:8.1.2 --restart=Never --command -- sleep 3600
kubectl get pods
# test     0/2     PodInitializing
# test     2/2     Running
Enter the pod and attempt to curl Wikipedia again:
kubectl exec -ti test -- /bin/sh
curl --head -L http://www.wikipedia.org
Because meshConfig.outboundTrafficPolicy.mode is REGISTRY_ONLY and www.wikipedia.org is not yet registered in Istio, Envoy will block the request and return:
HTTP/1.1 502 Bad Gateway
date: ...
server: envoy
This demonstrates that REGISTRY_ONLY prevents egress unless a ServiceEntry (or other Istio configuration) explicitly allows the external host.
To permit pods in an Istio-enabled namespace to reach external services, add ServiceEntry resources (or configure egress gateways) for those hosts.

4. Create a ServiceEntry for Wikipedia

Register www.wikipedia.org with Istio by creating a ServiceEntry in the default namespace. Save this as serviceentry-wikipedia.yaml:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: wikipedia-egress
spec:
  hosts:
  - www.wikipedia.org
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
Apply the ServiceEntry and verify its creation:
kubectl apply -f serviceentry-wikipedia.yaml
kubectl get serviceentries.networking.istio.io
# NAME                HOSTS                     LOCATION    RESOLUTION   AGE
# wikipedia-egress    ["www.wikipedia.org"]     DNS                    14s
Retry from the test pod:
kubectl exec -ti test -- /bin/sh
curl --head -L http://www.wikipedia.org
Now the request should succeed (HTTP 200 after the redirect). The ServiceEntry allowed egress to that external host.

5. Route external traffic through an Istio egress gateway

Routing external traffic through an egress gateway centralizes outbound traffic, enabling monitoring, logging, and centralized policy enforcement. To route traffic through the egress gateway we need:
  • A Gateway resource that selects the egress gateway pods.
  • A DestinationRule pointing to the egress gateway service (and a subset).
  • A VirtualService that (a) routes mesh-originating traffic to the egress gateway and (b) routes traffic from the egress gateway to the external host.
Important: Gateway resources select pods in the same namespace as the Gateway. The built-in egress gateway pods live in istio-system, so create the Gateway in istio-system to match pods by label. First confirm the egress gateway pod and labels:
kubectl get pods -n istio-system --show-labels
# ... istio-egressgateway-...  labels include: istio=egressgateway ...
Create the Gateway (save as gateway.yaml):
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: istio-egressgateway
  namespace: istio-system
spec:
  selector:
    istio: egressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - www.wikipedia.org
Apply it and verify:
kubectl apply -f gateway.yaml
kubectl get gateways.networking.istio.io -n istio-system
# NAME                  AGE
# istio-egressgateway   12s
Create a DestinationRule that points to the egress gateway service (save as dr.yaml):
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: egressgateway-for-wikipedia
  namespace: default
spec:
  host: istio-egressgateway.istio-system.svc.cluster.local
  subsets:
  - name: wikipedia
Apply and confirm:
kubectl apply -f dr.yaml
kubectl get destinationrules.networking.istio.io
# NAME                         HOST                                                AGE
# egressgateway-for-wikipedia  istio-egressgateway.istio-system.svc.cluster.local  7s
Create the VirtualService (save as vs.yaml). This resource has two important HTTP blocks:
  1. A mesh gateway match for port 80: routes traffic originating inside the mesh to the egress gateway subset wikipedia.
  2. An istio-system/istio-egressgateway gateway match: routes traffic arriving at the egress gateway to the external host www.wikipedia.org.
Note: Because the Gateway is in istio-system, reference it in the VirtualService as istio-system/istio-egressgateway.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: wikipedia-egress-gateway
spec:
  hosts:
  - www.wikipedia.org
  gateways:
  - istio-system/istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        subset: wikipedia
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - istio-system/istio-egressgateway
    port: 80
    route:
    - destination:
        host: www.wikipedia.org
        port:
          number: 80
      weight: 100
Apply the VirtualService and verify:
kubectl apply -f vs.yaml
kubectl get virtualservices.networking.istio.io
# NAME                       GATEWAYS                                      HOSTS
# wikipedia-egress-gateway   ["istio-system/istio-egressgateway","mesh"]   ["www.wikipedia.org"]
Important explanation: The mesh gateway entry is required so that traffic originating from inside the mesh (pod → external host) matches the first HTTP rule and is routed to the egress gateway subset wikipedia. When the egress gateway receives the request, the VirtualService matches the istio-system/istio-egressgateway gateway rule and forwards the request to www.wikipedia.org. If you omit the mesh match, internal traffic will bypass the egress gateway and will not be centrally controlled.
If you omit the mesh gateway entry in the VirtualService, traffic from inside the mesh will bypass the egress gateway, removing centralized control and visibility.

6. Observe traffic through the egress gateway

Tail logs for the egress gateway pod in another terminal:
kubectl logs -f -n istio-system <istio-egressgateway-pod-name>
# Look for entries like:
# "HEAD / HTTP/2" 301 - via_upstream ... "www.wikipedia.org" ...
From the test pod, curl Wikipedia again:
kubectl exec -ti test -- /bin/sh
curl --head -L http://www.wikipedia.org
You should see normal responses, and the egress gateway logs will show the outbound request. This confirms that mesh traffic was routed to the egress gateway which then forwarded it to the external host.

Quick reference: resources for egress control

Resource TypePurposeExample / Notes
ServiceEntryRegister external host(s) with Istio to allow egress under REGISTRY_ONLYSee serviceentry-wikipedia.yaml above
GatewaySelects egress gateway pods (namespace-specific) and exposes ports/hostsCreate in istio-system to select istio=egressgateway pods
DestinationRulePoints to the egress gateway service and defines subsetsHost should be istio-egressgateway.istio-system.svc.cluster.local
VirtualServiceRoutes mesh-originating traffic to egress gateway and gateway→external hostInclude both mesh and istio-system/istio-egressgateway in gateways

Additional ServiceEntry examples

Simple external HTTP ServiceEntry:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-svc-httpbin
  namespace: egress
spec:
  hosts:
  - example.com
  exportTo:
  - "."
  location: MESH_EXTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
External TLS ServiceEntry for multiple hosts:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-svc-https
spec:
  hosts:
  - api.dropboxapi.com
  - www.googleapis.com
  - api.facebook.com
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS
ServiceEntry pointing to fixed IP endpoints (Mongo example):
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-svc-mongocluster
spec:
  hosts:
  - mymongodb.somedomain
  addresses:
  - 192.192.192.192/24
  ports:
  - number: 27018
    name: mongodb
    protocol: MONGO
  location: MESH_INTERNAL
  resolution: STATIC
  endpoints:
  - address: 2.2.2.2
  - address: 3.3.3.3
Generic egress Gateway snippet:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: istio-egressgateway
  namespace: istio-system
spec:
  selector:
    istio: egressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

Troubleshooting tips

  • If your VirtualService isn’t taking effect, confirm the Gateway exists in the correct namespace and the gateways entry in the VirtualService is properly namespace-qualified (istio-system/istio-egressgateway).
  • If traffic is still blocked after creating a ServiceEntry, ensure the ServiceEntry is in the same namespace as the client pod (or exported appropriately) and that DNS resolution is working as expected.
  • Use kubectl get virtualservices,destinationrules,gateways,serviceentries -A to verify configuration across namespaces.

Summary

  • Setting meshConfig.outboundTrafficPolicy.mode to REGISTRY_ONLY blocks egress to hosts not registered in Istio.
  • Use ServiceEntry to register external hosts so Istio allows egress.
  • To centralize and control external traffic, create an egress Gateway, a DestinationRule pointing to the egress gateway service, and a VirtualService that routes mesh-originating traffic to the egress gateway and the gateway to the external host.
  • The mesh gateway entry in the VirtualService is essential to route traffic originating from inside the mesh through the egress gateway.
Practice creating these resources (ServiceEntry, Gateway, DestinationRule, VirtualService) so you can apply them swiftly in real-world scenarios and assessments.

Watch Video

Practice Lab