Chapter 3. Directing outbound traffic through a gateway Using Istio APIs, you can configure gateway proxies that were installed using gateway injection to direct traffic that is bound for an external service. 3.1. About directing egress traffic through a gateway You can configure a gateway installed using gateway injection as an exit point for the traffic leaving a service mesh. In this configuration, the gateway acts as a forward proxy for requests sent to the services that are external to the mesh. Configuring a gateway for egress traffic can help fulfill security requirements. For example, an egress gateway can be used in environments where traffic restrictions require that all traffic exiting a mesh flows through a dedicated set of nodes. Similarly, a gateway can be used when network policies prevent application nodes from directly accessing external services. In such scenarios, gateway proxies are deployed on dedicated egress nodes capable of accessing external services. These nodes can then be subjected to strict network policy enforcement or additional monitoring to enhance security. To configure a gateway installed using gateway injection to direct the egress traffic, use a combination of the Istio ServiceEntry , Gateway , VirtualService , and DestinationRule resources. Use the ServiceEntry resource to define the properties of an external service. The external service is added to the Istio service registry for the mesh. This enables you to apply Istio features, such as monitoring and routing rules, to the traffic exiting the mesh that is destined for an external service. Use the Gateway , VirtualService , and DestinationRule resources to set up rules that route traffic from the mesh to the external service using the gateway proxy. 3.2. Directing egress traffic through a gateway using Istio APIs Use Istio APIs to direct outbound HTTP traffic through a gateway that was installed using gateway injection. Prerequisites You have installed a gateway using gateway injection. Procedure Create a namespace called curl by running the following command: USD oc create namespace curl Depending on the update strategy you are using, enable sidecar injection in the namespace by running the appropriate commands: If you are using the InPlace update strategy, run the following command: USD oc label namespace curl istio-injection=enabled If you are using the RevisionBased update strategy, run the following commands: Display the revision name by running the following command: USD oc get istiorevisions.sailoperator.io Example output NAME TYPE READY STATUS IN USE VERSION AGE default-v1-23-0 Local True Healthy True v1.23.0 3m33s Label the namespace with the revision name to enable sidecar injection by running the following command: USD oc label namespace curl istio.io/rev=default-v1-23-0 Deploy a curl application by running the following command: USD oc apply -n curl -f https://raw.githubusercontent.com/openshift-service-mesh/istio/refs/heads/master/samples/curl/curl.yaml Export a CURL_POD environment variable that has been initialized with the name of the curl pod: USD export CURL_POD=USD(oc get pod -n curl -l app=curl -o jsonpath='{.items[0].metadata.name}') Create a YAML file named http-se.yaml that directs traffic from the mesh to an external service. The following example defines a ServiceEntry for a URL. Example configuration apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: egress-se namespace: curl spec: hosts: - docs.redhat.com ports: - number: 80 name: http-port protocol: HTTP location: MESH_EXTERNAL resolution: DNS Apply the YAML file by running the following command: USD oc apply -f http-se.yaml Ensure the ServiceEntry configuration was applied correctly. Send an HTTP request to the host that you specified in the step by running the following command: USD oc exec "USDCURL_POD" -n curl -c curl -- curl -sSL -o /dev/null -D - http://docs.redhat.com This command should return HTTP status codes, such as 301 (redirect) or 200 (success), indicating that the connection works. Create a YAML file named http-gtw.yaml that creates an egress Gateway and routes traffic from the mesh to the host specified for the external service. Example configuration apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: egress-gw namespace: <gateway_namespace> # Namespace where the egress gateway is deployed spec: selector: istio: <gateway_name> # Selects the egress-gateway instance to handle this traffic servers: - port: number: 80 name: http protocol: HTTP hosts: - docs.redhat.com # External service host, not a full URL. --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egress-dr namespace: <gateway_namespace> # Namespace where the egress gateway is deployed spec: host: <gateway_name>.<gateway_namespace>.svc.cluster.local subsets: - name: rh-docs Apply the YAML file by running the following command: USD oc apply -f http-gtw.yaml Create a YAML file named http-vs.yaml that sets up a VirtualService to manage the flow of traffic from the application sidecars through the egress gateway to the external host. Example configuration apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: egress-vs namespace: curl # Namespace where the curl pod is running spec: hosts: - docs.redhat.com # External service host, not a full URL. gateways: - mesh - <gateway_namespace>/egress-gw # Egress gateway name defined in the file that you used in the step. http: - match: - gateways: - mesh port: 80 route: - destination: host: <gateway_name>.<gateway_namespace>.svc.cluster.local subset: rh-docs port: number: 80 weight: 100 - match: - gateways: - <gateway_namespace>/egress-gw # Egress gateway name defined in the file that you used in the step. port: 80 route: - destination: host: docs.redhat.com port: number: 80 weight: 100 Apply the YAML file by running the following command: USD oc apply -f http-vs.yaml Resend the HTTP request to the URL: USD oc exec "USDCURL_POD" -n curl -c curl -- curl -sSL -o /dev/null -D - http://docs.redhat.com The terminal should display information similar to the following output: Example output ... HTTP/1.1 301 Moved Permanently ... location: <example_url> ... HTTP/2 200 Content-Type: text/html; charset=utf-8 Ensure that the request was routed through the gateway by running the following command: USD oc logs deployment/<gateway_name> -n <gateway_namespace> | tail -1 Note Access logging must be enabled for this verification step to work. You can enable access logging to the standard output by setting the spec.values.meshConfig.accessLogFile field to /dev/stdout in the Istio resource. The terminal should display information similar to the following output: Example output [2024-11-07T14:35:52.428Z] "GET / HTTP/2" 301 - via_upstream - "-" 0 0 24 24 "10.128.2.30" "curl/8.11.0" "79551af2-341b-456d-b414-9220b487a03b" "docs.redhat.com" "23.55.176.201:80" outbound|80||docs.redhat.com 10.128.2.29:49766 10.128.2.29:80 10.128.2.30:38296 -

Commands:
oc create namespace curl
oc label namespace curl istio-injection=enabled
oc get istiorevisions.sailoperator.io
NAME TYPE READY STATUS IN USE VERSION AGE default-v1-23-0 Local True Healthy True v1.23.0 3m33s
oc label namespace curl istio.io/rev=default-v1-23-0
oc apply -n curl -f https://raw.githubusercontent.com/openshift-service-mesh/istio/refs/heads/master/samples/curl/curl.yaml
export CURL_POD=USD(oc get pod -n curl -l app=curl -o jsonpath='{.items[0].metadata.name}')
apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: egress-se namespace: curl spec: hosts: - docs.redhat.com ports: - number: 80 name: http-port protocol: HTTP location: MESH_EXTERNAL resolution: DNS
oc apply -f http-se.yaml
oc exec "USDCURL_POD" -n curl -c curl -- curl -sSL -o /dev/null -D - http://docs.redhat.com
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: egress-gw namespace: <gateway_namespace> # Namespace where the egress gateway is deployed spec: selector: istio: <gateway_name> # Selects the egress-gateway instance to handle this traffic servers: - port: number: 80 name: http protocol: HTTP hosts: - docs.redhat.com # External service host, not a full URL. --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egress-dr namespace: <gateway_namespace> # Namespace where the egress gateway is deployed spec: host: <gateway_name>.<gateway_namespace>.svc.cluster.local subsets: - name: rh-docs
oc apply -f http-gtw.yaml
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: egress-vs namespace: curl # Namespace where the curl pod is running spec: hosts: - docs.redhat.com # External service host, not a full URL. gateways: - mesh - <gateway_namespace>/egress-gw # Egress gateway name defined in the file that you used in the previous step. http: - match: - gateways: - mesh port: 80 route: - destination: host: <gateway_name>.<gateway_namespace>.svc.cluster.local subset: rh-docs port: number: 80 weight: 100 - match: - gateways: - <gateway_namespace>/egress-gw # Egress gateway name defined in the file that you used in the previous step. port: 80 route: - destination: host: docs.redhat.com port: number: 80 weight: 100
oc apply -f http-vs.yaml
oc exec "USDCURL_POD" -n curl -c curl -- curl -sSL -o /dev/null -D - http://docs.redhat.com
HTTP/1.1 301 Moved Permanently location: <example_url> HTTP/2 200 Content-Type: text/html; charset=utf-8
oc logs deployment/<gateway_name> -n <gateway_namespace> | tail -1
[2024-11-07T14:35:52.428Z] "GET / HTTP/2" 301 - via_upstream - "-" 0 0 24 24 "10.128.2.30" "curl/8.11.0" "79551af2-341b-456d-b414-9220b487a03b" "docs.redhat.com" "23.55.176.201:80" outbound|80||docs.redhat.com 10.128.2.29:49766 10.128.2.29:80 10.128.2.30:38296 -