Egress TLS origination with client certificate in 1.7 using SDS does not work and the docs are confusing


I have a very simple use case: I want to call an external service from my pod and use egress gateway to apply a client certificate to the outgoing request (TLS origination). I don’t want to verify any certificates.

I can easily achieve it using stunnel with a following simple configuration:
client = yes
accept = 8181
connect = destination:443
cert = /certs/certificate.pem
key = /certs/private.key

When I call (HTTP) stunnel:8181/something, stunnel will do the TLS upgrade, use the client certificate and forward the request to (HTTPS) destination:443/something

I have been trying to set this up using Egress Gateway since istio 1.3. My latest attempt with istio 1.7 and SDS (auto mTLS disabled) has been also unsuccessful:

I need a ServiceEntry, Gateway, DestinationRule and a VirtualService just to setup the traffic flow through the Egress Gateway. This works fine and my Egress Gateway forwards the request to the correct destination.
To enable the TLS origination, I need to create a secret with the certificate (in istio-system namespace) + an additional Destination Rule.

According to the link above, the Secret should be created like this:

> kubectl create secret generic gibaskbx-client-cacert --from-file=certificate.pem -n istio-system

However, the istio-proxy logs then shows warnings and errors:

2020-09-03T13:58:14.045870Z warn secretfetcher failed load CA only secret from gibaskbx-client-cacert: no ‘cacert’ or ‘tls.crt’ key in the secret
2020-09-03T13:58:14.045908Z info secretfetcher Fail to extract secret gibaskbx-client-cacert found by direct api call
2020-09-03T13:58:14.045917Z warn secretfetcher Cannot find secret gibaskbx-client-cacert, searching for fallback secret gateway-fallback
2020-09-03T13:58:14.045926Z error secretfetcher cannot find secret gibaskbx-client-cacert and cannot find fallback secret gateway-fallback

When I create the secret like this, the error goes away:

kubectl create secret tls gibaskbx-client-cacert -n istio-system

In both cases, TLS origination does not work.

This is my DestinationRule:

apiVersion: networking.istio .io/v1alpha3
kind: DestinationRule
name: originate-tls-for-gibaskbx
- port:
number: 443
mode: SIMPLE
credentialName: gibaskbx-client # this must match the secret created earlier without the “-cacert” suffix

And this is how I test it (using deliberately https://):

kubectl exec -it $SOURCE_POD -c sleep -n platform – curl -k -v -sL -o /dev/null -D -

The result is:

* Trying…
* Connected to webapi.developers.erstegroup .com ( port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: none
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to webapi.developers.erstegroup .com:443
* Closing connection 0
command terminated with exit code 35

Without applying the final DestinationRule, I get error code 56 at the very end of the TLS handshake, but that seems to be expected:

* OpenSSL SSL_read: SSL_ERROR_ SYSCALL, errno 0
* Closing connection 0
command terminated with exit code 56

My Gateway uses tls mode: PASSTHROUGH if that’s of any significance.


  1. Has anyone achieved a working TLS origination like this?
  2. Why should the Secret holding the client certificate be named with -cacert as a suffix?
  3. Should the Secret holding the client certificate be a tls secret or a generic secret? What about the key?
  4. Isn’t it too complex to setup such a simple use case? (compared to stunnel)?!?