Skip to content
You are viewing the documentation for Solo Enterprise for Istio, formerly known as Gloo Mesh (OSS APIs).

Egress

Page as Markdown

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

  1. Set up a sidecar mesh by using the Gloo Operator or Helm.
  2. 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.

  1. If you have not already, set the following environment variables.

    1. Save the Solo distribution of Istio patch version and tag that you installed.
      export ISTIO_VERSION=1.30.3
      # Change the tags as needed
      export ISTIO_IMAGE=${ISTIO_VERSION}-solo
    2. Save the image and Helm repository information for the Solo distribution of Istio.
      • Istio 1.29 and later:
        export REPO=us-docker.pkg.dev/soloio-img/istio
        export HELM_REPO=us-docker.pkg.dev/soloio-img/istio-helm
      • Istio 1.28 and earlier: Save the repo key for the minor version of the Solo distribution of Istio that you want to install. 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}
    3. Get the revision that you used for your installation. Typically, this is main for a Helm installation, or gloo 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}
    4. 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 cluster where you installed a service mesh.
      export CLUSTER_NAME=<cluster-name>
      export ctx=<cluster-context>
  2. 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/doc-examples/main/istio/sidecar/egress-gateway.yaml > egress-gateway.yaml
    envsubst < egress-gateway.yaml > egress-gateway-values.yaml
  3. Create the egress gateway.

    helm upgrade --install istio-egressgateway oci://${HELM_REPO}/gateway \
      --version ${ISTIO_VERSION} \
      --namespace istio-egress \
      --create-namespace \
      --kube-context ${ctx} \
      --wait \
      -f egress-gateway-values.yaml
  4. 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.

  1. 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
  2. Send a request from the productpage app to httpbin.org. This request succeeds because the ServiceEntry enables outgoing requests to httpbin.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
    ...
  3. 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
  4. 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
  5. Repeat the request from the productpage app to httpbin.org. Verify that your response contains the X-Envoy-Peer-Metadata-Id header with a value similar to router~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
    ...
  6. 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.

  1. Create an AuthorizationPolicy that allows only GET requests to the httpbin.org service. You apply this policy to the egress gateway by using the targetRefs 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
  2. Send a POST request to httpbin.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
  3. 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.

  1. 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
  2. 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.

  1. Add targetPort: 443 to your ServiceEntry to instruct the egress gateway to use port 443 when routing traffic to 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:
      - number: 80
        name: http
        protocol: HTTP
        targetPort: 443 
      resolution: DNS
    EOF
  2. 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
  3. Send a request to the httpbin.org external service and verify that traffic is sent to https://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

  • Install the Solo UI to review your resources and traffic between services in the mesh.
  • When it’s time to upgrade your service mesh, you can perform a safe in-place upgrade by using the Gloo Operator or Helm.