Cannot intercept TLS traffic with istio egress gateway

I am trying to intercept generic TLS traffic (including HTTPS) directed to external applications with the istio egress gateway. The reason is that I want to be able to define which source pods can access a given set of external resources.
I have already tried the TLS origination approach by following the procedure described in Istio / Egress Gateways with TLS Origination (File Mount) . While this approach seems to work most of the time, I would still like to be able to send encrypted traffic directly from my application.

Now, I’m wondering if it is possible at all to do something like that. I would imagine the flow to be like this: Pod X wants to access an external service (e.g., google), the egress gateway intercepts the traffic and then it sends it to the intended destination. Now, this works if I use PASSTHROUGH as tls mode on the Gateway. However, this won’t allow me to enforce policies of any kind, because the gateway will just let traffic flow without inspecting it.

This is why I tried to setup ISTIO_MUTUAL as tls mode. This works perfectly with generic tcp traffic, but I would like to do it for TLS as well in order to rely on DNS resolution of domains (with generic tcp traffic I have to assign the ip addresses manually, which is not always sustainable. With TLS I should be able to rely on SNIs). So, the flow would look like the following: Pod X encrypts some traffic that is already encrypted (application encryption + mutual TLS), it sends it to the egress gateway, the egress gateway decrypts the mutual TLS layer (without trying to understand the content since it is encrypted), it decides whether to allow or deny such traffic (since now it is able to determine the source pod identity and AuthorizationPolicies can be used easily) and it sends the traffic to the intended (external) destination (if the source pod matches an allow policy).

Is this possible? The only reference that I found is Istio Prelim 1.11 / Consuming External MongoDB Services , and I followed it quite accurately without any success. It looks like the traffic does not even get to the egress gateway. Is this approach completely wrong and should TLS origination be used instead, all the times? What would be an alternative to filter encrypted traffic sent directly by a pod?

Here are some configuration details.
I am using istio 1.9.2 and I installed it with the istio operator.
I deployed an additional egress gateway with the IstioOperator:

    egressGateways:
      - enabled: true
        k8s:
          service:
            ports:
              - name: tls
                port: 443
        label:
          app: istio-egressgateway-tls
          istio: istio-egressgateway-tls
        name: istio-egressgateway-tls

This generates an associated deployment and a service:

apiVersion: v1
kind: Service
metadata:
  annotations:
  labels:
    app: istio-egressgateway-tls
    install.operator.istio.io/owning-resource: istiocontrolplane
    install.operator.istio.io/owning-resource-namespace: istio-system
    istio: istio-egressgateway-tls
    istio.io/rev: default
    operator.istio.io/component: EgressGateways
    operator.istio.io/managed: Reconcile
    operator.istio.io/version: 1.9.2
    release: istio
  name: istio-egressgateway-tls
  namespace: istio-system
spec:
  clusterIP: 10.33.7.154
  ports:
  - name: tls
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    app: istio-egressgateway-tls
    istio: istio-egressgateway-tls
  sessionAffinity: None
  type: ClusterIP

Here are all the manifests that I used to configure the egress gateway (it’s based on Istio / Egress Gateways with TLS Origination (File Mount) ):

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: egress-gw-tls
  namespace: istio-system
  annotations:
    argocd.argoproj.io/sync-wave: "-1"
    argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
  selector:
    istio: istio-egressgateway-tls
  servers:
    - hosts:
        - www.google.com
      port:
        number: 443
        name: tls
        protocol: TLS
      tls:
        mode: ISTIO_MUTUAL

---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: google-test
  namespace: istio-system
spec:
  host: istio-egressgateway-tls.istio-system.svc.cluster.local
  subsets:
    - name: google-test-subset
      trafficPolicy:
        portLevelSettings:
          - port:
              number: 443
            tls:
              mode: ISTIO_MUTUAL
              sni: www.google.com

---
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: google-test
  namespace: istio-system
spec:
  hosts:
    - www.google.com
  ports:
    - number: 443
      name: tls
      protocol: TLS
  location: MESH_EXTERNAL
  resolution: DNS

---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: google-test
  namespace: istio-system
spec:
  hosts:
    - www.google.com
  gateways:
    - mesh
    - istio-system/egress-gw-tls
  tls:
    - match:
        - gateways:
            - mesh
          port: 443
          sniHosts:
            - www.google.com
      route:
        - destination:
            host: istio-egressgateway-tls.istio-system.svc.cluster.local
            subset: google-test-subset
            port:
              number: 443
          weight: 100
  tcp:
    - match:
        - gateways:
            - istio-system/egress-gw-tls
          port: 443
      route:
        - destination:
            host: www.google.com
            port:
              number: 443
          weight: 100

---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-all-tls
  namespace: istio-system
spec:
  rules:
    - {}
  selector:
    matchLabels:
      istio: istio-egressgateway-tls

Some Debugging info

  1. I spawn a container with an istio sidecar that is able to forward traffic.
    If I curl www.google.com:
root@command-demo-privileged-57c9c99d77-5sgrm:/# curl https://www.google.com
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.google.com:443

I see nothing in the egress gateway logs. In the command-demo-privileged-57c9c99d77-5sgrm sidecar logs I see:

{
  "response_code_details": null,
  "bytes_received": 0,
  "authn_source_principal": null,
  "authn_email": null,
  "downstream_local_address": "172.217.168.4:443",
  "start_time": "2021-06-11T14:53:38.606Z",
  "upstream_service_time": null,
  "authn_name": null,
  "bytes_sent": 0,
  "method": null,
  "request_id": null,
  "upstream_cluster": "outbound|443|google-test-subset|istio-egressgateway-tls.istio-system.svc.cluster.local",
  "downstream_remote_address": "10.32.13.216:35314",
  "protocol": null,
  "authority": null,
  "duration": 2,
  "authn_upn": null,
  "connection_termination_details": null,
  "upstream_local_address": null,
  "user_agent": null,
  "requested_server_name": null,
  "route_name": null,
  "x_forwarded_for": null,
  "upstream_host": "10.32.3.56:443",
  "response_flags": "UF,URX",
  "authn_request_auth_principal": null,
  "upstream_transport_failure_reason": null,
  "path": null,
  "response_code": 0
}
  1. If I use telnet
root@command-demo-privileged-57c9c99d77-5sgrm:/# telnet www.google.com 443
Trying 172.217.168.4...
Connected to www.google.com.
Escape character is '^]'.

^CConnection closed by foreign host.

I see nothing in the egress gateway logs and in the sidecar container it’s pretty clear that traffic is being sent through the passthrough cluster:

{
  "downstream_local_address": "172.217.168.4:443",
  "bytes_received": 9,
  "authn_upn": null,
  "route_name": null,
  "method": null,
  "authn_name": null,
  "upstream_host": "172.217.168.4:443",
  "authn_email": null,
  "requested_server_name": null,
  "upstream_local_address": "10.32.13.216:39622",
  "upstream_service_time": null,
  "upstream_transport_failure_reason": null,
  "downstream_remote_address": "10.32.13.216:39256",
  "authn_source_principal": null,
  "protocol": null,
  "user_agent": null,
  "connection_termination_details": null,
  "x_forwarded_for": null,
  "start_time": "2021-06-11T14:55:29.970Z",
  "upstream_cluster": "PassthroughCluster",
  "bytes_sent": 7,
  "path": null,
  "request_id": null,
  "authn_request_auth_principal": null,
  "authority": null,
  "response_code": 0,
  "duration": 11333,
  "response_code_details": null,
  "response_flags": "-"
}

Unfortunately, this is as far as I can go. I don’t have additional ideas about things that I could check. Any pointer would be appreciated.

Regarding to the error of “OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.google.com”, you may turn on curl verbose debugging flags to get more details of the error.