Mutual TLS: External Clients to the Gateway

This task demonstrates how mutual TLS can be achieved between external clients and the Gateway. This task uses a self-signed CA, so it should be used for testing and demonstration purposes only.


  • OpenSSL to generate TLS assets.


Follow the steps from the Quickstart to install Envoy Gateway and the example manifest. Before proceeding, you should be able to query the example backend using HTTP.

TLS Certificates

Generate the certificates and keys used by the Gateway to terminate client TLS connections.

Create a root certificate and private key to sign certificates:

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./' -keyout -out

Create a certificate and a private key for

openssl req -out -newkey rsa:2048 -nodes -keyout -subj "/ organization"
openssl x509 -req -days 365 -CA -CAkey -set_serial 0 -in -out

Store the cert/key in a Secret:

kubectl create secret tls example-cert

Store the CA Cert in another Secret:

kubectl create secret generic example-ca-cert

Create a certificate and a private key for the client

openssl req -out -newkey rsa:2048 -nodes -keyout -subj "/ organization"
openssl x509 -req -days 365 -CA -CAkey -set_serial 0 -in -out

Update the Gateway from the Quickstart to include an HTTPS listener that listens on port 443 and references the example-cert Secret:

kubectl patch gateway eg --type=json --patch '
  - op: add
    path: /spec/listeners/-
      name: https
      protocol: HTTPS
      port: 443
        mode: Terminate
          - kind: Secret
            group: ""
            name: example-cert

Verify the Gateway status:

kubectl get gateway/eg -o yaml

Create a ClientTrafficPolicy to enforce client validation using the CA Certificate as a trusted anchor.

cat <<EOF | kubectl apply -f -
kind: ClientTrafficPolicy
  name: enable-mtls
  namespace: default
    kind: Gateway
    name: eg
    namespace: default
      - kind: "Secret"
        group: ""
        name: "example-ca-cert"


Clusters without External LoadBalancer Support

Get the name of the Envoy service created the by the example Gateway:

export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system, -o jsonpath='{.items[0]}')

Port forward to the Envoy service:

kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8443:443 &

Query the example app through Envoy proxy:

curl -v --resolve "" \
--cert --key \

Clusters with External LoadBalancer Support

Get the External IP of the Gateway:

export GATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')

Query the example app through the Gateway:

curl -v --resolve "${GATEWAY_HOST}" \
--cert --key \

Dont specify the client key and certificate in the above command, and ensure that the connection fails

curl -v --resolve "${GATEWAY_HOST}" \

Last modified May 25, 2024: fix api wording (#3467) (5bc5e0f)