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.

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.28.5
      # Change the tags as needed
      export ISTIO_IMAGE=${ISTIO_VERSION}-solo
      ```<ol start="2">
  • Save the repo key for the minor version of the Solo distribution of Istio. 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 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}
    1. 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}
    2. 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>
    3. 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
    4. 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
    5. 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.