Skip to content

For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.

Backend TLS

Page as Markdown

Originate a one-way TLS connection from the Gateway to a backend.

Originate a one-way TLS connection from the Gateway to a backend.

About one-way TLS

When you configure a TLS listener on your Gateway, the Gateway typically terminates incoming TLS traffic and forwards the unencrypted traffic to the backend service. However, you might have a service that only accepts TLS connections, or you want to forward traffic to a secured Backend service that is external to the cluster.

You can use the Kubernetes Gateway API BackendTLSPolicy to configure TLS origination from the Gateway to a service in the cluster. This policy supports simple, one-way TLS use cases.

However, to additionally set up different hostnames on the Backend that you want to route to via SNI, or to originate TLS connections to an external backend, use the kgateway BackendConfigPolicy instead.

About this guide

In this guide, you learn how to use the BackendTLSPolicy and BackendConfigPolicy resources to originate one-way TLS connections for the following services:

  • In-cluster service: An NGINX server that is configured with a self-signed TLS certificate and deployed to the same cluster as the Gateway. You use a BackendTLSPolicy to originate TLS connections to NGINX.
  • External service: The httpbin.org hostname, which represents an external service that you want to originate a TLS connection to. You use a BackendConfigPolicy resource to originate TLS connections to that hostname.

Before you begin

  1. Follow the Get started guide to install kgateway.

  2. Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.

  3. Get the external address of the gateway and save it in an environment variable.

    export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
    echo $INGRESS_GW_ADDRESS  

In-cluster service

Deploy an NGINX server in your cluster that is configured for TLS traffic. Then, instruct the gateway proxy to terminate TLS traffic at the gateway and originate a new TLS connection from the gateway proxy to the NGINX server.

Deploy the sample app

The following example uses an NGINX server with a self-signed TLS certificate. For the configuration, see the test directory in the kgateway GitHub repository.

  1. Create the namespace.

    kubectl create namespace kgateway-base
  2. Deploy the NGINX server with a self-signed TLS certificate.

    kubectl apply -f https://raw.githubusercontent.com/kgateway-dev/kgateway/refs/heads/main/test/e2e/features/backendtls/testdata/nginx.yaml
  3. Verify that the NGINX server is running.

    kubectl -n kgateway-base get pods -l app.kubernetes.io/name=nginx

    Example output:

    NAME    READY   STATUS    RESTARTS   AGE
    nginx   1/1     Running   0          9s

Create a TLS policy

Create a TLS policy for the NGINX workload. You can use the Gateway API BackendTLSPolicy for simple, one-way TLS connections. For more advanced TLS connections or simply to reduce the number of resources if you use other backend connections, create a BackendConfigPolicy instead.

  1. Create a Kubernetes Secret that has the public CA certificate for the NGINX server.

    kubectl apply -f- <<EOF
    apiVersion: v1
    kind: Secret
    metadata:
      namespace: kgateway-base
      name: ca
      labels:
        app: nginx
    type: Opaque
    stringData:
      ca.crt: |
        -----BEGIN CERTIFICATE-----
        MIIDFTCCAf2gAwIBAgIUIlv+uw9O1gTwKnf4HvCIFusHWh4wDQYJKoZIhvcNAQEL
        BQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjYwNzA3MTY0OTM2WhcNMzYw
        NzA0MTY0OTM2WjAWMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN
        AQEBBQADggEPADCCAQoCggEBAJJiw/saYoXDnvJ2hgLGErN/DEOU7NCFE7h5tECa
        8uTmBV2m2bXnlXjg6umB0rPsKSOnSpF2qCt64Ll7I+/kODyu/VkuhYA/ki5Wi32V
        uFU7scb1FwbuhNL1/zq6hRhpsqajmpt6Q7ndpfp1mVXx/dblsufV6dyODkjenU97
        BukkLXar+G0KBouw1MNqLzN9y6ISuo0BvEvfLBUi0b9NuNXmtICrffBHzVNBf7Sx
        7KEW4nSO+55AoLJnAga6X0ZvSQju9GXE9iyrV4YRY51fwW/E+jU4GYOlUQow7bEI
        fOJDupwoUuFsUthhMCNpnJS955hxPFjqmeWJCJs0rTNoU1UCAwEAAaNbMFkwFgYD
        VR0RBA8wDYILZXhhbXBsZS5jb20wCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsG
        AQUFBwMBMB0GA1UdDgQWBBQRB7nN8rfErGTItgws/E8EPzPSIjANBgkqhkiG9w0B
        AQsFAAOCAQEAH63LT5aquDjz13D4HuXGiJlXyBnTmYQ5yQRbioeWJp3msai12/MJ
        /St1T4CyhWV5pUAUDdpjsjgAZjGxntYdw/fs4bJbLqnbKGC5ujObxwZ/tzbPvm+v
        t0UH8beP4ba5wKzwqeWu3sWMNPwoxyzIRQpInZPSxnqYe/7ataB93d3wLS/AcuU6
        Lijsx/zJXw0xNoyfJjvqdI0cSoV6lyYggxul06Mc5d08NNeck/gObDc3Ku2IapN3
        Ith7RWjemymjJw/gQZguqctyRnBaAZZrFES8s6Acqsxa3Ee9Oyk+9OZs6wnXWscZ
        cmk3NzvSnsKQt+jTR3DZWdUR5Iua0WP6xw==
        -----END CERTIFICATE-----
    EOF
  2. Create the TLS policy.

    kubectl apply -f- <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: BackendConfigPolicy
    metadata:
      namespace: kgateway-base
      name: nginx-tls-policy
      labels:
        app: nginx
    spec:
      targetRefs:
      - group: ""
        kind: Service
        name: nginx
      tls:
        sni: "example.com"
        secretRef:
          name: ca
    EOF

    Review the following table to understand this configuration. For more information, see the BackendConfigPolicy API docs.

    SettingDescription
    targetRefsThe service that you want the Gateway to originate a TLS connection to, such as the NGINX server.

    Agentgateway proxies: Even if you use a Backend for selector-based destinations, you still need to target the backing Service and the sectionName of the port that you want the policy to apply to.
    tls.sniThe Server Name Indication (SNI) hostname that matches the NGINX server certificate. The SNI is used during the TLS handshake to specify which certificate the server should present.
    tls.secretRefThe Kubernetes Secret that has the public CA certificate for the NGINX server.

Create an HTTPRoute

Create an HTTPRoute that routes traffic to the NGINX server on the example.com hostname and HTTPS port 8443. Note that the parent Gateway is the sample http Gateway resource that you created before you began.

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  namespace: kgateway-base
  name: nginx-route
  labels:
    app: nginx
spec:
  parentRefs:
  - name: http
    namespace: kgateway-system
  hostnames:
  - "example.com"
  rules:
  - backendRefs:
    - name: nginx
      port: 8443
EOF

Verify the TLS connection

Now that your TLS backend and routing resources are configured, verify the TLS connection.

  1. Send a request to the NGINX server and verify that you get back a 200 HTTP response code.

    curl -vi http://$INGRESS_GW_ADDRESS:8080/ -H "host: example.com:8080"

    Example output:

    * Host localhost:8080 was resolved.
    * IPv6: ::1
    * IPv4: 127.0.0.1
    *   Trying [::1]:8080...
    * Connected to localhost (::1) port 8080
    > GET / HTTP/1.1
    > Host: example.com:8080
    > User-Agent: curl/8.7.1
    > Accept: */*
    > 
    * Request completely sent off
    < HTTP/1.1 200 OK
    HTTP/1.1 200 OK
  2. Enable port-forwarding on the Gateway.

    kubectl port-forward deploy/http -n kgateway-system 19000
  3. In your browser, open the Envoy stats page at http://127.0.0.1:19000/stats.

  4. Search for the following stats that indicate the TLS connection is working. The count increases each time that the Gateway sends a request to the NGINX server.

    • cluster.kube_kgateway-base_nginx_8443.ssl.versions.TLSv1.2: The number of TLSv1.2 connections from the Envoy gateway proxy to the NGINX server.
    • cluster.kube_kgateway-base_nginx_8443.ssl.handshake: The number of successful TLS handshakes between the Envoy gateway proxy and the NGINX server.

External service

Set up a Backend resource that represents your external service. Then, use a BackendTLSPolicy or BackendConfigPolicy to instruct the gateway proxy to originate a TLS connection from the gateway proxy to the external service.

Note

If your gateway proxy runs inside an Istio service mesh, Istio’s automatic mTLS can override the TLS settings from your BackendTLSPolicy or BackendConfigPolicy, causing backend TLS connections to fail. To prevent this failure, add the kgateway.dev/disable-istio-auto-mtls: "true" annotation to the Backend resource. For more information, see Istio ingress.

  1. Create a Backend resource that represents your external service. In this example, you use a static Backend that routes traffic to the httpbin.org site. Make sure to include the HTTPS port 443 so that traffic is routed to this port.

    kubectl apply -f- <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: Backend
    metadata:
      name: httpbin-org
      namespace: default
    spec:
      type: Static
      static:
        hosts:
        - host: httpbin.org
          port: 443
    EOF
  2. Create a TLS policy that originates a TLS connection to the Backend that you created in the previous step. To originate the TLS connection, you use known trusted CA certificates. You can use the Gateway API BackendTLSPolicy for simple, one-way TLS connections. For more advanced TLS connections or simply to reduce the number of resources if you use other backend connections, create a BackendConfigPolicy instead. Note that the BackendConfigPolicy is only supported for Envoy-based kgateway proxies.

    kubectl apply -f- <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: BackendConfigPolicy
    metadata:
      name: httpbin-org
      namespace: default
    spec:
      targetRefs:
        - name: httpbin-org
          kind: Backend
          group: gateway.kgateway.dev
      tls:
        sni: httpbin.org
        wellKnownCACertificates: System
    EOF
  3. Create an HTTPRoute that rewrites traffic on the httpbin-external.example domain to the httpbin.org hostname and routes traffic to your Backend.

    kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin-org
      namespace: default
    spec:
      parentRefs:
      - name: http
        namespace: kgateway-system
      hostnames:
      - "httpbin-external.example"
      rules:
        - matches:
          - path:
              type: PathPrefix
              value: /anything
          backendRefs:
          - name: httpbin-org
            kind: Backend
            group: gateway.kgateway.dev
          filters:
          - type: URLRewrite
            urlRewrite:
              hostname: httpbin.org
    EOF
  4. Send a request to the httpbin-external.example domain. Verify that the host is rewritten to https://httpbin.org/anything and that you get back a 200 HTTP response code.

    curl -vi http://$INGRESS_GW_ADDRESS:8080/anything -H "host: httpbin-external.example" 

    Example output:

    < HTTP/1.1 200 OK
    HTTP/1.1 200 OK
    ...
    {
      "args": {}, 
      "data": "", 
      "files": {}, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Host": "httpbin.org", 
        "User-Agent": "curl/8.7.1", 
        "X-Amzn-Trace-Id": "Root=1-6881126a-03bfc90450805b9703e66e78", 
        "X-Envoy-Expected-Rq-Timeout-Ms": "15000", 
        "X-Envoy-External-Address": "10.0.15.215"
      }, 
      "json": null, 
      "method": "GET", 
      "origin": "10.0.X.XXX, 3.XXX.XXX.XXX", 
      "url": "https://httpbin.org/anything"
    }
    

Other configurations

Review other configurations.

TLS settings

Restrict the TLS settings that the gateway proxy uses when it originates the upstream TLS connection, such as the key exchange curves, the TLS version range, and the signature algorithms. These settings are useful when your backend requires specific parameters for compliance or security reasons, such as a P-384 ECDSA server certificate that the Envoy default ECDH curve list rejects. If you do not set a parameter, the Envoy default applies.

Set the parameters in the same policy that you created for the TLS connection in this guide. When a backend has both a BackendTLSPolicy and a BackendConfigPolicy, the BackendTLSPolicy takes precedence for TLS and the BackendConfigPolicy TLS settings are ignored.

The following examples update the nginx-tls-policy that you created earlier. The values in the examples are illustrative. Adjust them to match what your backend supports.

kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: BackendConfigPolicy
metadata:
  name: nginx-tls-policy
  namespace: kgateway-base
spec:
  targetRefs:
  - group: ""
    kind: Service
    name: nginx
  tls:
    sni: "example.com"
    secretRef:
      name: ca
    parameters:
      ecdhCurves:
      - P-384
      - P-256
      cipherSuites:
      - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
      - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
      minVersion: "1.2"
      maxVersion: "1.3"
      signatureAlgorithms:
      - ecdsa_secp256r1_sha256
      - rsa_pss_rsae_sha256
    alpnProtocols:
    - http/1.1
    verifySubjectAltNames:
    - example.com
EOF
Review the following table to understand this configuration.
SettingDescription
tls.parameters.ecdhCurvesThe key exchange curves for the upstream TLS handshake. If the backend uses a P-384 ECDSA certificate, include P-384 in this list.
tls.parameters.cipherSuitesThe cipher suites for the upstream TLS handshake. Cipher suites apply to TLS 1.2 and earlier.
tls.parameters.minVersionThe minimum TLS version for the upstream TLS handshake.
tls.parameters.maxVersionThe maximum TLS version for the upstream TLS handshake.
tls.parameters.signatureAlgorithmsThe TLS signature algorithms that the gateway proxy advertises during the upstream TLS handshake.
tls.alpnProtocolsThe Application-Layer Protocol Negotiation (ALPN) protocols that the gateway proxy offers to the backend. If you do not set this field, the proxy offers h2 and http/1.1.
tls.verifySubjectAltNamesA list of Subject Alternative Names. The backend certificate must have one of these names. This setting requires a trusted CA certificate in tls.secretRef.

Cleanup

You can remove the resources that you created in this guide.

In-cluster service

  1. Delete the NGINX server.

    kubectl delete -f https://raw.githubusercontent.com/kgateway-dev/kgateway/refs/heads/main/test/e2e/features/backendtls/testdata/nginx.yaml
  2. Delete the routing resources that you created for the NGINX server.

    kubectl -n kgateway-base delete backendconfigpolicy,secret,httproute -A -l app=nginx

External service

Delete the resources that you created.

kubectl delete httproute httpbin-org
kubectl delete backendconfigpolicy httpbin-org
kubectl delete backend httpbin-org
Was this page helpful?