Notice:
This is the "latest" release of Envoy Gateway, which contains the most recent commits from the main branch.
This release might not be stable.
Please refer to the /docs documentation for the most current information.

Backend TLS: Skip TLS Verification

This task demonstrates how to skip TLS verification for a backend service in Envoy Gateway.

By default, you must configure a BackendTLSPolicy to validate the TLS certificate of a backend service when it uses TLS.

However, in certain scenarios—such as development or testing—you might want to skip TLS verification for a backend service. To do this, you can use the Backend API and set the tls.insecureSkipVerify field to true in the Backend resource.

Warning: Skipping TLS verification disables certificate validation, which can expose your connection to man-in-the-middle attacks. This setting is typically used only for development or testing and is not recommended in production environments.

Prerequisites

  • OpenSSL to generate TLS assets.

Installation

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

Expand for instructions
  1. Install the Gateway API CRDs and Envoy Gateway using Helm:

    helm install eg oci://docker.io/envoyproxy/gateway-helm --version v0.0.0-latest -n envoy-gateway-system --create-namespace
    
  2. Install the GatewayClass, Gateway, HTTPRoute and example app:

    kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/latest/quickstart.yaml -n default
    
  3. Verify Connectivity:

    Get the External IP of the Gateway:

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

    Curl the example app through Envoy proxy:

    curl --verbose --header "Host: www.example.com" http://$GATEWAY_HOST/get
       

    The above command should succeed with status code 200.

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

    export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
       

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

    export ENVOY_DEPLOYMENT=$(kubectl get deploy -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
       

    Port forward to the Envoy service:

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

    Curl the example app through Envoy proxy:

    curl --verbose --header "Host: www.example.com" http://localhost:8888/get
       

    The above command should succeed with status code 200.

Enable Backend

The Backend API is disabled by default in Envoy Gateway. To enable it, follow the steps outlined in Backend Routing to configure the EnvoyGateway startup settings accordingly.

TLS Certificates

Generate the certificates and keys used by the backend to terminate TLS connections from the Gateways.

Create a root certificate and private key to sign certificates:

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

Create a certificate and a private key for www.example.com.

First, create an openssl configuration file:

cat > openssl.conf  <<EOF
[req]
req_extensions = v3_req
prompt = no

[v3_req]
keyUsage = keyEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.example.com
EOF

Then create a certificate using this openssl configuration file:

openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization"
openssl x509 -req -days 365 -CA ca.crt -CAkey ca.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt -extfile openssl.conf -extensions v3_req

Note that the certificate must contain a DNS SAN for the relevant domain.

Store the cert/key in a Secret:

kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crt

Store the CA Cert in another Secret:

kubectl create configmap example-ca --from-file=ca.crt

Setup TLS on the backend

Patch the existing quickstart backend to enable TLS. The patch will mount the TLS certificate secret into the backend as volume.

kubectl patch deployment backend --type=json --patch '
  - op: add
    path: /spec/template/spec/containers/0/volumeMounts
    value:
    - name: secret-volume
      mountPath: /etc/secret-volume
  - op: add
    path: /spec/template/spec/volumes
    value:
    - name: secret-volume
      secret:
        secretName: example-cert
        items:
        - key: tls.crt
          path: crt
        - key: tls.key
          path: key
  - op: add
    path: /spec/template/spec/containers/0/env/-
    value:
      name: TLS_SERVER_CERT
      value: /etc/secret-volume/crt
  - op: add
    path: /spec/template/spec/containers/0/env/-
    value:
      name: TLS_SERVER_PRIVKEY
      value: /etc/secret-volume/key
  '

Create a service that exposes port 443 on the backend service.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  labels:
    app: backend
    service: backend
  name: tls-backend
  namespace: default
spec:
  selector:
    app: backend
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8443
EOF

Save and apply the following resource to your cluster:

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: backend
    service: backend
  name: tls-backend
  namespace: default
spec:
  selector:
    app: backend
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8443

Skip TLS Verification

In the following example, we will create a Backend resource that routes to the tls-backend service, and an HTTPRoute that references the Backend resource.

cat <<EOF | kubectl apply -f -
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: backend
spec:
  parentRefs:
    - name: eg
  hostnames:
    - "www.example.com"
  rules:
    - backendRefs:
        - group: gateway.envoyproxy.io
          kind: Backend
          name: tls-backend
      matches:
        - path:
            type: PathPrefix
            value: /
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: tls-backend
  namespace: default
spec:
  endpoints:
    - fqdn:
        hostname: tls-backend.default.svc.cluster.local
        port: 443
EOF

Save and apply the following resources to your cluster:

---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: backend
spec:
  parentRefs:
    - name: eg
  hostnames:
    - "www.example.com"
  rules:
    - backendRefs:
        - group: gateway.envoyproxy.io
          kind: Backend
          name: tls-backend
      matches:
        - path:
            type: PathPrefix
            value: /
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: tls-backend
  namespace: default
spec:
  endpoints:
    - fqdn:
        hostname: tls-backend.default.svc.cluster.local
        port: 443

Send a request to the backend service:

curl -v -HHost:www.example.com --resolve "www.example.com:80:${GATEWAY_HOST}" \
http://www.example.com:80/get

Because the backend service is using TLS, and no BackendTLSPolicy is configured to validate the TLS certificate, the request will fail with a 400 Bad Request error:

* Connected to www.example.com (172.18.0.200) port 80
* using HTTP/1.x
> GET /get HTTP/1.1
> Host:www.example.com
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 400 Bad Request
< date: Thu, 31 Jul 2025 06:09:51 GMT
< transfer-encoding: chunked

Disabling TLS verification by setting the InsecureSkipVerify field to true allows the request to succeed:

cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: tls-backend
  namespace: default
spec:
  endpoints:
    - fqdn:
        hostname: tls-backend.default.svc.cluster.local
        port: 443
  tls:
    insecureSkipVerify: true
EOF
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: tls-backend
  namespace: default
spec:
  endpoints:
    - fqdn:
        hostname: tls-backend.default.svc.cluster.local
        port: 443
  tls:
    insecureSkipVerify: true

Send the request again:

curl -v -HHost:www.example.com --resolve "www.example.com:80:${GATEWAY_HOST}" \
http://www.example.com:80/get

You should now see a successful response from the backend service. Since TLS verification has been skipped, the request proceeds without validating the backend’s TLS certificate. The response will include TLS details such as the protocol version and cipher suite used for the connection.

< HTTP/1.1 200 OK
[...]
 "tls": {
  "version": "TLSv1.2",
  "serverName": "",
  "negotiatedProtocol": "http/1.1",
  "cipherSuite": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
 }