Egress
Route all traffic through an egress gateway and enforce policies before traffic leaves your sidecar mesh.
The options to deploy an egress gateway vary based on the traffic management API that you want to use.
Kubernetes Gateway API
To use the Kubernetes Gateway API custom resources to configure traffic management in your service mesh, you can deploy Gateway resources that expose your services. For more information about using the Gateway API in Istio, see this blog post.
To use the Kubernetes Gateway API, you can follow the Egress gateways guide in the community Istio docs. Be sure to use the Gateway API resources option in the steps.
Using the Kubernetes Gateway API for an egress gateway requires using experimental versions of the Gateway API CRDs. To use the experimental Gateway API with Istio, you must also modify your Istio installation, such as to add required environment variables.
Istio networking API
To use the classic Istio networking API to configure traffic management in your service mesh, you can deploy an Istio egress gateway by using Helm.
Before you begin
- Set up a sidecar mesh by using the Gloo Operator or Helm.
- Add services to the sidecar mesh. The guide walks you through an example for how to install the Bookinfo app and add it to your service mesh.
Step 1: Create an egress gateway
Use the Istio networking API to configure an Istio egress gateway by using Helm.
If you have not already, set the following environment variables.
- Save the Solo distribution of Istio patch version and tag that you installed.
export ISTIO_VERSION=1.26.2 # Change the tags as needed export ISTIO_IMAGE=${ISTIO_VERSION}-solo
- Save the repo key for the minor version of the Solo distribution of Istio that you installed. This is the 12-character hash at the end of the repo URL
us-docker.pkg.dev/gloo-mesh/istio-<repo-key>
, which you can find in the Istio images built by Solo.io support article.# 12-character hash at the end of the minor version repo URL export REPO_KEY=<repo_key> export REPO=us-docker.pkg.dev/gloo-mesh/istio-${REPO_KEY} export HELM_REPO=us-docker.pkg.dev/gloo-mesh/istio-helm-${REPO_KEY}
- Get the revision that you used for your installation. Typically, this is
main
for a Helm installation, orgloo
for a Gloo Operator installation.export REVISION=$(kubectl get pod -l app=istiod -n istio-system -o jsonpath='{.items[0].metadata.labels.istio\.io/rev}') echo ${REVISION}
- Save the name and kubeconfig context of a cluster where you want to install the egress gateway. In a multicluster setup, this can be any workload cluster where you installed a service mesh.
export CLUSTER_NAME=<cluster-name> export CLUSTER_CONTEXT=<cluster-context>
- Save the Solo distribution of Istio patch version and tag that you installed.
Prepare a Helm values file for the Istio egress gateway. This sample command downloads an example file,
egress-gateway.yaml
, and updates the environment variables with the values that you previously set. You can further edit the file to provide your own details for production-level settings.curl -0L https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/gloo-mesh-enterprise/istio-install/manual-helm/egress-gateway.yaml > egress-gateway.yaml envsubst < egress-gateway.yaml > egress-gateway-values.yaml
Create the egress gateway.
helm upgrade --install istio-egressgateway oci://${HELM_REPO}/gateway \ --version ${ISTIO_VERSION} \ --namespace istio-egress \ --create-namespace \ --kube-context ${CLUSTER_CONTEXT} \ --wait \ -f egress-gateway-values.yaml
Verify that your egress gateway pod is running.
kubectl get pods -n istio-egress
Example output:
NAME READY STATUS RESTARTS AGE istio-egressgateway-5bfbdb5958-9svmt 1/1 Running 0 25s
Step 2: Route traffic through the egress gateway
Create ServiceEntry, Gateway, and DestinationRule resources to enable routing through the egress gateway to the httpbin.org
host. Then, create a VirtualService to configure sidecars in the mesh to always route egress traffic to the host through the egress gateway.
Create a ServiceEntry that represents the external service
httpbin.org
.kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: httpbin.org namespace: istio-egress spec: hosts: - httpbin.org ports: - name: http number: 80 protocol: HTTP resolution: DNS EOF
Send a request from the productpage app to
httpbin.org
. This request succeeds because the ServiceEntry enables outgoing requests tohttpbin.org
without the use of an egress gateway.kubectl -n bookinfo exec deploy/productpage-v1 -c curl -- curl -vik "httpbin.org/get"
Example output:
... < HTTP/1.1 200 OK < date: Thu, 05 Jun 2025 20:58:37 GMT < content-type: application/json < content-length: 941 < server: envoy < access-control-allow-origin: * < access-control-allow-credentials: true < x-envoy-upstream-service-time: 769 ...
Create dedicated Gateway and DestinationRule resources that route all outgoing traffic requests to
httpbin.org
on port 80.kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: Gateway metadata: name: istio-egressgateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - httpbin.org --- apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: egressgateway-for-httpbin.org namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: httpbin.org EOF
Create a VirtualService to configure sidecars in the mesh to always route egress traffic to
httpbin.org
through the egress gateway.kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: direct-httpbin.org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egressgateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: httpbin.org port: number: 80 weight: 100 - match: - gateways: - istio-egressgateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 EOF
Repeat the request from the productpage app to
httpbin.org
. Verify that your response contains theX-Envoy-Peer-Metadata-Id
header with a value similar torouter~10.XX.XX.XX~istio-egressgateway-5bfbdb5958-9svmt.istio-egress~istio-egress.svc.cluster.local
, which verifies that traffic is routed through the egress gateway.kubectl -n bookinfo exec deploy/productpage-v1 -c curl -- curl -vik "httpbin.org/get"
Example output:
... "X-Envoy-Peer-Metadata": "ChoKCkNMVVNURVJfSUQSDBoKS3ViZXJuZXRlcwqXAQoGTEFCRUxTEowBKokBChwKA2FwcBIVGhNpc3Rpby1lZ3Jlc3NnYXRld2F5CjgKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSFRoTaXN0aW8tZWdyZXNzZ2F0ZXdheQovCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIIGgYxLjI2LjAKLgoETkFNRRImGiRpc3Rpby1lZ3Jlc3NnYXRld2F5LTViZmJkYjU5NTgtOXN2bXQKGwoJTkFNRVNQQUNFEg4aDGlzdGlvLWVncmVzcwpcCgVPV05FUhJTGlFrdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvaXN0aW8tZWdyZXNzL2RlcGxveW1lbnRzL2lzdGlvLWVncmVzc2dhdGV3YXkKJgoNV09SS0xPQURfTkFNRRIVGhNpc3Rpby1lZ3Jlc3NnYXRld2F5", "X-Envoy-Peer-Metadata-Id": "router~10.0.79.208~istio-egressgateway-5bfbdb5958-9svmt.istio-egress~istio-egress.svc.cluster.local" }, "origin": "10.0.XX.XX, 35.169.103.7", "url": "http://httpbin.org/get" } * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < date: Thu, 05 Jun 2025 21:02:24 GMT < content-type: application/json < content-length: 1045 < server: envoy < access-control-allow-origin: * < access-control-allow-credentials: true < x-envoy-upstream-service-time: 3230 ...
Optional: If you enabled Istio access logs, you can review the logs of the egress gateway and verify that you can see a log entry for the request from productpage to
httpbin.org
through the egress gateway.kubectl logs -l istio=egressgateway -c istio-proxy -n istio-egress | tail
Example output:
{"authority":"httpbin.org","bytes_received":0,"bytes_sent":1045,"connection_termination_details":null,"downstream_local_address":"10.0.XX.XX:80","downstream_remote_address":"10.0.XX.XX:34760","duration":3226,"method":"GET","path":"/get","protocol":"HTTP/2","request_id":"c75481d6-a2df-4815-9a7b-7b94deba2097","requested_server_name":null,"response_code":200,"response_code_details":"via_upstream","response_flags":"-","route_name":null,"start_time":"2025-06-05T21:02:20.806Z","upstream_cluster":"outbound|80||httpbin.org","upstream_host":"52.202.28.30:80","upstream_local_address":"10.0.XX.XX:57306","upstream_service_time":"3226","upstream_transport_failure_reason":null,"user_agent":"curl/7.83.1-DEV","x_forwarded_for":"10.0.XX.XX"}
Step 3: Apply an egress policy
Now that all traffic to the httpbin.org
service is routed through the egress gateway, you can apply additional routing and security policies to it.
AuthorizationPolicy
In this example, you learn how to use an Istio AuthorizationPolicy to restrict access to the external service for specific HTTP methods.
Create an AuthorizationPolicy that allows only
GET
requests to thehttpbin.org
service. You apply this policy to the egress gateway by using thetargetRefs
section.kubectl apply -f - <<EOF apiVersion: security.istio.io/v1 kind: AuthorizationPolicy metadata: name: httpbin namespace: istio-egress spec: targetRefs: - kind: Gateway name: egress-waypoint group: gateway.networking.k8s.io action: ALLOW rules: - to: - operation: hosts: ["httpbin.org"] methods: ["GET"] paths: ["/get"] EOF
Send a
POST
request tohttpbin.org
and verify that this request is denied with a 405 HTTP response code.kubectl -n bookinfo exec deploy/productpage-v1 -c curl -- curl -vik "httpbin.org/post"
Example output:
... HTTP/1.1 405 Method Not Allowed date: Thu, 05 Jun 2025 21:08:43 GMT content-type: text/html content-length: 178 server: envoy allow: OPTIONS, POST access-control-allow-origin: * access-control-allow-credentials: true x-envoy-upstream-service-time: 1465
Repeat the request. This time, you use the
GET
HTTP method that is allowed by the AuthorizationPolicy. Verify that your request now succeeds.kubectl -n bookinfo exec deploy/productpage-v1 -c curl -- curl -vik "httpbin.org/get"
Example output:
... < HTTP/1.1 200 OK < date: Thu, 05 Jun 2025 20:58:37 GMT < content-type: application/json < content-length: 941 < server: envoy < access-control-allow-origin: * < access-control-allow-credentials: true < x-envoy-upstream-service-time: 769 ...
Header manipulation
In this example, you explore how to add headers to a request by using an Istio VirtualService.
Update the VirtualService to add the
my-added-header: added-value
header to your request.kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: direct-httpbin.org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egressgateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: httpbin.org port: number: 80 weight: 100 - match: - gateways: - istio-egressgateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 headers: request: add: my-added-header: added-value EOF
Send a request to the
httpbin.org
external service and verify that you see the added request header.kubectl -n bookinfo exec deploy/productpage-v1 -c curl -- curl -vik "httpbin.org/get"
Example output:
< HTTP/1.1 200 OK < date: Thu, 05 Jun 2025 21:10:41 GMT < content-type: application/json < content-length: 1084 < server: envoy < access-control-allow-origin: * < access-control-allow-credentials: true < x-envoy-upstream-service-time: 2533 < { [1084 bytes data] 100 1084 100 1084 0 0 42HTTP/1.1 200 OK02 0:00:02 --:--:-- 427 date: Thu, 05 Jun 2025 21:10:41 GMT content-type: application/json content-length: 1084 server: envoy access-control-allow-origin: * access-control-allow-credentials: true x-envoy-upstream-service-time: 2533 { "args": {}, "headers": { "Accept": "*/*", "Host": "httpbin.org", "My-Added-Header": "added-value", ...
TLS origination
By default, all traffic within your service mesh is secured via mutual TLS. However, when routing traffic through an egress gateway, the egress gateway terminates the TLS connection and forwards the unencrypted request to the external service.
With TLS origination, you instruct the egress gateway to re-encrypt the request before it is forwarded to the external service.
Add
targetPort: 443
to your ServiceEntry to instruct the egress gateway to use port 443 when routing traffic tohttpbin.org
.kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: httpbin.org namespace: istio-egress spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP targetPort: 443 resolution: DNS EOF
Create a DestinationRule to instruct the egress gateway to originate a TLS connection when routing traffic to
httpbin.org
.kubectl apply -f- <<EOF apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: httpbin.org-tls namespace: istio-egress spec: host: httpbin.org trafficPolicy: tls: mode: SIMPLE EOF
Send a request to the
httpbin.org
external service and verify that traffic is sent tohttps://httpbin.org/get
.kubectl -n bookinfo exec deploy/productpage-v1 -c curl -- curl -vik "httpbin.org/get"
Example output:
... { "args": {}, "headers": { "Accept": "*/*", "Host": "httpbin.org", "My-Added-Header": "added-value", "User-Agent": "curl/7.83.1-DEV", "X-Amzn-Trace-Id": "Root=1-68420852-036726fc21bb8eb76838deff", "X-Envoy-Attempt-Count": "1", "X-Envoy-External-Address": "10.0.XX.XX", "X-Envoy-Peer-Metadata": "ChoKCkNMVVNURVJfSUQSDBoKS3ViZXJuZXRlcwqXAQoGTEFCRUxTEowBKokBChwKA2FwcBIVGhNpc3Rpby1lZ3Jlc3NnYXRld2F5CjgKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSFRoTaXN0aW8tZWdyZXNzZ2F0ZXdheQovCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIIGgYxLjI2LjAKLgoETkFNRRImGiRpc3Rpby1lZ3Jlc3NnYXRld2F5LTViZmJkYjU5NTgtOXN2bXQKGwoJTkFNRVNQQUNFEg4aDGlzdGlvLWVncmVzcwpcCgVPV05FUhJTGlFrdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvaXN0aW8tZWdyZXNzL2RlcGxveW1lbnRzL2lzdGlvLWVncmVzc2dhdGV3YXkKJgoNV09SS0xPQURfTkFNRRIVGhNpc3Rpby1lZ3Jlc3NnYXRld2F5", "X-Envoy-Peer-Metadata-Id": "router~10.0.79.208~istio-egressgateway-5bfbdb5958-9svmt.istio-egress~istio-egress.svc.cluster.local" }, "origin": "10.0.XX.XX, 35.169.103.7", "url": "https://httpbin.org/get" }
Cleanup
You can optionally remove the resources that you created in this guide.
- Policies:
kubectl delete destinationrule httpbin.org-tls -n istio-egress kubectl delete authorizationpolicy httpbin -n istio-egress
- Gateway and routing resources:
kubectl delete virtualservice direct-httpbin.org-through-egress-gateway -n istio-egress kubectl delete destinationrule egressgateway-for-httpbin.org -n istio-egress kubectl delete gateway.networking.istio.io/istio-egressgateway -n istio-egress kubectl delete serviceentry httpbin.org -n istio-egress
- Istio egress gateway:
helm uninstall istio-egressgateway -n istio-egress kubectl delete namespace istio-egress
Next
- Launch the Gloo UI to review the Istio insights that were captured for your service mesh setup. Gloo Mesh comes with an insights engine that automatically analyzes your Istio setups for health issues. These issues are displayed in the UI along with recommendations to harden your Istio setups. The insights give you a checklist to address issues that might otherwise be hard to detect across your environment. For more information, see Insights.
- When it’s time to upgrade your service mesh, you can perform a safe in-place upgrade by using the Gloo Operator or Helm.