0

I have a VirtualService that splits traffic between an internal Service and an external ServiceEntry, based on HTTP route prefix.

The external service requires HTTPS traffic.

I test routes using curl like below:

curl https://my-service.domain.com/internal-route  -> should go to internal service

curl https://my-service.domain.com/external-route  -> should go to external service

What I tried so far:

  1. Use HTTP routes for both internal and external service.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
spec:
  gateways:
    - ...
  hosts:
    - my-service.domain.com
  http:
    - match:
        - uri:
            prefix: /internal-route
      route:
        - destination:
            host: my-service.my-ns.svc.cluster.local
    - match:
        - uri:
            prefix: /external-route
      route:
        - destination:
            host: external-service.otherdomain.com
---
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
spec:
  hosts:
    - external-service.otherdomain.com
  ports:
    - number: 443
      name: https
      protocol: HTTP
  location: MESH_EXTERNAL
  resolution: DNS

When I try this, the external service indicates that HTTP traffic is being sent to its HTTPS port (443). This makes sense, since Istio is terminating the TLS connection and using HTTP to forward the request to the external service.

  1. Using a "tls" match type (for external service) and "http" route (for internal service) within the same VirtualService.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
spec:
  gateways:
    - ...
  hosts:
    - my-service.domain.com
  http:
    - match:
        - uri:
            prefix: /internal-route
      route:
        - destination:
            host: my-service.my-ns.svc.cluster.local
  tls:
    - match:
        - port: 443
          sniHosts:
            - my-service.domain.com
      route:
        - destination:
            host: external-service.otherdomain.com
---
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
spec:
  hosts:
    - external-service.otherdomain.com
  ports:
    - number: 443
      name: https
      protocol: TLS
  location: MESH_EXTERNAL
  resolution: DNS

This results in Istio returning a HTTP 404 when I try to reach a route that should go to the external service.

  1. Same as above, with ServiceEntry protocol set to HTTP instead of TLS.

How can I configure Istio to terminate the TLS connection and then use HTTPS (via a new TLS connection) to send traffic to the external service?

EDIT 1:

I found in the Istio docs (one and two) that this should be possible by adding a DestinationRule, but this does not seem to have any effect.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: tls-foo
spec:
  host: external-service.otherdomain.com
  trafficPolicy:
    portLevelSettings:
      - port:
          number: 80
        tls:
          mode: SIMPLE
GreenGiant
  • 4,930
  • 1
  • 46
  • 76
  • You can try redirect to external url. may be this will help https://stackoverflow.com/a/68152336/19246531 or https://istio.io/latest/docs/tasks/traffic-management/egress/egress-control/#direct-access-to-external-services – Nataraj Medayhal Jul 12 '23 at 09:57
  • @Nataraj Unless I am misunderstanding, the Stack Overflow link is what I already tried above. I can try the multiple gateways approach. – GreenGiant Jul 12 '23 at 18:42

2 Answers2

0

404 errors in Istio occurs mainly because of following reasons as mentioned in the official Istio troubleshooting documents

- Gateway to virtual service TLS mismatch

- When multiple gateways are configured with same TLS certificate

In your case it might be caused due to Gateway to virtual service TLS mismatch, the reason is you are trying to use two different types of routing rules in the same virtual service. There are two types of mismatches that cause these 404 errors


- Gateway TLS termination: In this scenario TLS will be getting terminated by the gateway while might have configured TLS based routes in VirtualService. This can be verified by using `istioctl proxy-config routes` command.

- Gateway TLS passthrough: This occurs when the http traffic is getting matched with the TLS traffic passed through the gateway by the VirtualService. This can be verified by using the `istioctl proxy-config listener` and `istioctl proxy-config route` commands.

Follow the official documentation embedded above for more information on how to fix these issues.

Note: The commands are taken from Istio official docs.

  • What does the `protocol` config on the ServiceEntry do? I thought it would control whether Istio uses HTTP vs HTTPS to send traffic to the external service, but it seems that Istio always uses HTTP. – GreenGiant Jul 11 '23 at 15:11
  • In answer to my last comment, the [Istio docs](https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/) say that `Because the Sidecar does not decrypt TLS traffic, this (https) is the same as tls` – GreenGiant Jul 11 '23 at 17:49
  • The `Protocol` field in a ServiceEntry mainly deals with the **L4** protocol used for traffic, but it doesn't directly control whether Istio uses http or https. VirtualServices, Destination rules and gateways controls whether istio uses http or https. – Kranthiveer Dontineni Jul 11 '23 at 18:09
  • For resolving this conflict configuration you can use two different gateways, go through this [article](https://learncloudnative.com/blog/2020-01-09-deploying_multiple_gateways_with_istio) written by `Peter Jausovec` for more information on how to configure multiple gateways in istio. – Kranthiveer Dontineni Jul 11 '23 at 18:20
  • Thanks @Kranthiveer. Is it possible to configure two different gateways to service the same host, on different URLs? – GreenGiant Jul 11 '23 at 20:47
  • @GreenGiant Yes it's possible, as per this [discussion](https://discuss.istio.io/t/attaching-multiple-gateways-to-istios-ingressgateway/5294/8) on the official forum you can have two different gateways on the same host but on different namespaces. – Kranthiveer Dontineni Jul 12 '23 at 04:25
  • Above you said "VirtualServices, Destination rules and gateways controls whether istio uses http or https." If that is the case, can you tell me why the configuration I have isn't causing Istio to use HTTPS? Specifically, what part of the Gateway configuration tells Istio to originate a new TLS/HTTPS connection? – GreenGiant Jul 12 '23 at 18:45
  • @GreenGiant As you see in your configuration you have a single gateway and two match rules with different protocols i.e., http and tls. since all the traffic is passing through the single gateway it is unable to distinguish the difference. So, as I said above if you have one gateway for http and one for tls it will help you in resolving the issue – Kranthiveer Dontineni Jul 13 '23 at 04:50
  • If I want some traffic to be unterminated TLS, then yes I think you're right. But I want all traffic to be TLS terminated at the gatway. What I'm asking is how to get Istio to initiate (originate) a new TLS connection when sending traffic to the ServiceEntry. – GreenGiant Jul 13 '23 at 19:46
  • @GreenGiant then I think you can try [Egress TLS Origination](https://istio.io/latest/docs/tasks/traffic-management/egress/egress-tls-origination) feature in Istio. TLS origination occurs when an Istio proxy (sidecar or egress gateway) is configured to accept unencrypted internal HTTP connections, encrypt the requests, and then forward them to HTTPS servers that are secured using simple or mutual TLS. – Kranthiveer Dontineni Jul 14 '23 at 04:55
  • As far as I can tell, those instructions match what I already have in my ServiceEntry and DestinationRule. Am I missing something? – GreenGiant Jul 14 '23 at 20:49
  • @GreenGiant In the `Egress TLS Origination` documentation inside the ServiceEntry there are using the protocol as https and in the destination rule they are using TLS. So the traffic passing through the gateway will be of http traffic and it won't be conflicting, whereas in your case you are using match conditions one with http and other with tls hence there is a conflict. So try to configure as mentioned in the TLS origination documentation and it will work. – Kranthiveer Dontineni Jul 17 '23 at 11:33
0

Below is the configuration that I finally found to work.

Key items to note:

  • DestinationRule tls mode SIMPLE is what "turns on" TLS origination
    • The port number selects which traffic the DestinationRule applies to
    • Therefore, it must match the port number in the other configs (see below)
  • The port number must be the same in all these places:
    • DestinationRule trafficPolicy.portLevelSettings
    • VirtualService http.route.destination
    • ServiceEntry ports.number
  • ServiceEntry ports.protocol doesn't seem to matter

The actual port number you use above doesn't matter. If you use something other than port 433, add a targetPort of 443 to ServiceEntry. This changes the port number to the standard 443 for HTTPS before making the connection to the external service. (Below, I just used 443 everywhere for simplicity.)

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
spec:
  gateways:
    - ...
  hosts:
    - my-service.domain.com
  http:
    - name: "internal-routes"
      match:
        - uri:
            prefix: "/internal"
      route:
        - destination:
            host: my-service.my-ns.svc.cluster.local
    - name: "external-routes"
      match:
        - uri:
            prefix: "/external"
      rewrite:
        authority: external.otherdomain.com
      route:
        - destination:
            host: external.otherdomain.com
            port:
              number: 443 # Can be anything
                          # Must match DestinationRule and ServiceEntry
                          # Can be overridden by ServiceEntry targetPort
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
spec:
  host: external.otherdomain.com
  trafficPolicy:
    portLevelSettings:
      - port:
          number: 443  # selects traffic on port 443 to host above
        tls:
          mode: SIMPLE # turns on TLS origination for selected traffic
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
spec:
  hosts:
    - external.otherdomain.com
  ports:
    - number: 443       # specifies that host above accepts traffic on this port
      name: http        # ignored
      protocol: HTTPS   # ignored
      # targetPort: 443 # only needed if not 443 above
  location: MESH_EXTERNAL
  resolution: DNS
GreenGiant
  • 4,930
  • 1
  • 46
  • 76