For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
BackendTLS
Verified Code examples on this page have been automatically tested and verified.Originate one-way TLS connections from the Gateway to backend services.
Originate a one-way TLS connection from the Gateway to a backend.
Warning
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.
CA certificate sources
In a BackendTLSPolicy, the CA certificate that verifies the backend must come from a Kubernetes ConfigMap. The gateway rejects a validation.caCertificateRefs entry that refers to any other kind of resource.
If you keep your CA certificates in Kubernetes Secrets, such as when a Secret is issued by cert-manager or synced from an external secret store, use the AgentgatewayPolicy resource instead. The tls.caCertificateRefs field in this resource takes an optional kind setting that you can set to ConfigMap (the default) or Secret. Either source must provide the certificate in a ca.crt key. For an example, see CA certificate in a Secret.
The tls.caCertificateRefs field is available in each place that the AgentgatewayPolicy and AgentgatewayBackend resources configure backend TLS, such as spec.backend.tls in a policy, spec.policies.tls in a backend, and the per-target policies.tls settings of an MCP or LLM backend.
About this guide
In this guide, you learn how 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.orghostname, which represents an external service that you want to originate a TLS connection to. You use a BackendTLSPolicy resource to originate TLS connections to that hostname. - CA certificate in a Secret: The same NGINX server, but with the CA certificate stored in a Kubernetes Secret instead of a ConfigMap. You use an AgentgatewayPolicy to originate TLS connections to NGINX.
Before you begin
Follow the Get started guide to install agentgateway.
Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.
Get the external address of the gateway and save it in an environment variable.
Tip
Kind cluster? Kind does not support
LoadBalancerservices by default. To use this option with a Kind cluster, install and runcloud-provider-kind.export INGRESS_GW_ADDRESS=$(kubectl get svc -n agentgateway-system agentgateway-proxy -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.
Create sample certificates
Create a CA and a server certificate for the example.com hostname. If you already have your own certificates such as from a CA provider, update the steps accordingly.
Warning
Self-signed certificates are used for demonstration purposes. Do not use self-signed certificates in production environments. Instead, use certificates that are issued from a trusted Certificate Authority.
Create the
example_certsdirectory and navigate to this directory.mkdir -p example_certs && cd example_certsCreate self-signed certificates for the Certificate Authority (CA) that you later use to sign the server certificate.
# Create CA private key openssl genrsa -out ca-key.pem 2048 # Create CA certificate (valid for 1 year) openssl req -new -x509 -days 365 -key ca-key.pem -out ca-cert.pem \ -subj "/CN=Test CA/O=Test Org"Create a server certificate for the
example.comhostname that is signed by the CA that you created in the previous step.# Create server private key openssl genrsa -out server-key.pem 2048 # Create server certificate signing request openssl req -new -key server-key.pem -out server.csr \ -subj "/CN=example.com/O=Test Org" # Create server certificate signed by CA (valid for 1 year) openssl x509 -req -days 365 -in server.csr -CA ca-cert.pem -CAkey ca-key.pem \ -CAcreateserial -out server-cert.pem \ -extensions v3_req -extfile <(echo "[v3_req]"; \ echo "basicConstraints=CA:FALSE"; \ echo "keyUsage=digitalSignature,keyEncipherment"; \ echo "extendedKeyUsage=serverAuth"; \ echo "subjectAltName=DNS:example.com,DNS:*.example.com")
Deploy the sample app
Deploy an NGINX server that serves HTTPS traffic. The NGINX server presents the server certificate, and the gateway proxy later uses the CA certificate to verify it.
Store the server certificate and key in a Kubernetes secret that the NGINX server mounts.
kubectl create secret tls nginx-server-cert \ --cert=server-cert.pem \ --key=server-key.pem \ -n agentgateway-systemDeploy the NGINX server and a Service that exposes it on HTTPS port 8443.
kubectl apply -f- <<EOF apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf namespace: agentgateway-system labels: app: nginx data: nginx.conf: | events {} http { server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/certs/tls.crt; ssl_certificate_key /etc/nginx/certs/tls.key; location / { return 200 "hello from nginx\n"; } } } --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: agentgateway-system labels: app: nginx spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: nginx template: metadata: labels: app.kubernetes.io/name: nginx spec: containers: - name: nginx image: nginx:stable ports: - containerPort: 443 name: https-web-svc volumeMounts: - name: nginx-conf mountPath: /etc/nginx/nginx.conf subPath: nginx.conf - name: server-cert mountPath: /etc/nginx/certs readOnly: true volumes: - name: nginx-conf configMap: name: nginx-conf - name: server-cert secret: secretName: nginx-server-cert --- apiVersion: v1 kind: Service metadata: name: nginx namespace: agentgateway-system labels: app: nginx spec: selector: app.kubernetes.io/name: nginx ports: - protocol: TCP port: 8443 targetPort: https-web-svc name: https EOF
Verify that the NGINX server is running.
kubectl get pods -l app.kubernetes.io/name=nginx -n agentgateway-systemExample output:
NAME READY STATUS RESTARTS AGE nginx-7c8f9d5b4c-x2vlq 1/1 Running 0 9s
Originate TLS connections
Create a BackendTLSPolicy for the NGINX workload.
Create a Kubernetes ConfigMap that has the CA certificate the Gateway uses to verify the NGINX server. The CA certificate must be in the
ca.crtkey.kubectl create configmap ca \ --from-file=ca.crt=ca-cert.pem \ -n agentgateway-systemCreate the TLS policy. Note that to use the BackendTLSPolicy, you must have the experimental channel of the Kubernetes Gateway API version 1.4 or later.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: tls-policy namespace: agentgateway-system labels: app: nginx spec: targetRefs: - group: "" kind: Service name: nginx validation: hostname: "example.com" caCertificateRefs: - group: "" kind: ConfigMap name: ca EOFReview the following table to understand this configuration. For more information, see the Kubernetes Gateway API docs.
Setting Description 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 thesectionNameof the port that you want the policy to apply to.validation.hostnameThe hostname that matches the NGINX server certificate. The gateway verifies this hostname against the Subject Alternative Names (SANs) or Common Name (CN) in the server certificate. validation.caCertificateRefsThe ConfigMap that has the CA certificate used to verify the backend, in a ca.crtkey. For the NGINX deployment in this guide, use the CA that signed the NGINX server certificate.Create an HTTPRoute that routes traffic to the NGINX server on the
example.comhostname and HTTPS port 8443. Note that the parent Gateway is the samplehttpGateway resource that you created before you began.kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: nginx-route namespace: agentgateway-system labels: app: nginx spec: parentRefs: - name: agentgateway-proxy namespace: agentgateway-system hostnames: - "example.com" rules: - backendRefs: - name: nginx port: 8443 EOFSend a request to the NGINX server and verify that you get back a 200 HTTP response code.
curl -vi http://$INGRESS_GW_ADDRESS:80/ -H "host: example.com:80"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 OKThe HTTPRoute forwards the request to the NGINX server on port 8443, and the NGINX server accepts only TLS on that port. A 200 response means that the gateway proxy originated a TLS connection to the backend successfully. Without a valid BackendTLSPolicy and CA certificate, requests fail with
invalid peer certificate: UnknownIssuer.
External service
Set up an AgentgatewayBackend resource that represents your external service. Then, use a BackendTLSPolicy to instruct the gateway proxy to originate a TLS connection from the gateway proxy to the external service.
Create an AgentgatewayBackend resource that represents your external service. In this example, you use a static backend that routes traffic to the
httpbin.orgsite. Make sure to include the HTTPS port 443 so that traffic is routed to this port.kubectl apply -f- <<EOF apiVersion: agentgateway.dev/v1alpha1 kind: AgentgatewayBackend metadata: name: httpbin-org namespace: agentgateway-system spec: static: host: httpbin.org port: 443 EOFCreate a TLS policy that originates a TLS connection to the AgentgatewayBackend that you created in the previous step. To originate the TLS connection, you use known trusted CA certificates.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: httpbin-org namespace: agentgateway-system spec: targetRefs: - name: httpbin-org kind: AgentgatewayBackend group: agentgateway.dev validation: hostname: httpbin.org wellKnownCACertificates: System EOFCreate an HTTPRoute that rewrites traffic on the
httpbin-external.exampledomain to thehttpbin.orghostname and routes traffic to your Backend.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-org namespace: agentgateway-system spec: parentRefs: - name: agentgateway-proxy namespace: agentgateway-system hostnames: - "httpbin-external.example" rules: - matches: - path: type: PathPrefix value: /anything backendRefs: - name: httpbin-org kind: AgentgatewayBackend group: agentgateway.dev filters: - type: URLRewrite urlRewrite: hostname: httpbin.org EOFSend a request to the
httpbin-external.exampledomain. Verify that the host is rewritten tohttps://httpbin.org/anythingand that you get back a 200 HTTP response code.curl -vi http://$INGRESS_GW_ADDRESS:80/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.X.XXX" }, "json": null, "method": "GET", "origin": "10.0.X.XXX, 3.XXX.XXX.XXX", "url": "https://httpbin.org/anything" }
CA certificate in a Secret
A BackendTLSPolicy reads the CA certificate only from a ConfigMap. To verify a backend by using a CA certificate that is stored in a Kubernetes Secret, use the AgentgatewayPolicy resource instead, and set kind: Secret in the caCertificateRefs field.
This section reuses the NGINX server and the nginx-route HTTPRoute that you created in the In-cluster service section.
Delete the BackendTLSPolicy that you created earlier so that the AgentgatewayPolicy is the only source of backend TLS settings for the NGINX server.
kubectl delete backendtlspolicy tls-policy -n agentgateway-system --ignore-not-foundCreate a Kubernetes Secret that has the same CA certificate that you stored in the ConfigMap earlier. The certificate must be in the
ca.crtkey, which is the same key that a ConfigMap source uses.kubectl create secret generic nginx-ca \ --from-file=ca.crt=ca-cert.pem \ -n agentgateway-systemCreate an AgentgatewayPolicy that originates TLS to the NGINX server and verifies the server certificate by using the Secret.
kubectl apply -f- <<EOF apiVersion: agentgateway.dev/v1alpha1 kind: AgentgatewayPolicy metadata: name: nginx-backend-tls namespace: agentgateway-system labels: app: nginx spec: targetRefs: - group: "" kind: Service name: nginx sectionName: "8443" backend: tls: caCertificateRefs: - name: nginx-ca kind: Secret sni: example.com verifySubjectAltNames: - example.com EOFReview the following table to understand this configuration. For more information, see the API docs.
Setting Description targetRefsThe Service that you want the Gateway to originate a TLS connection to. Use sectionNameto select the port that the policy applies to. For a Service,sectionNamemust be the numeric port, such as"8443", and not the name of the port.backend.tls.caCertificateRefsThe CA certificate source that has the certificate used to verify the backend, in a ca.crtkey. SetkindtoSecretto read the certificate from a Kubernetes Secret, or omitkindto read it from a ConfigMap. The gateway does not fall back between sources, so if a Secret and a ConfigMap have the same name, only the source that thekindfield selects is used.backend.tls.sniThe Server Name Indication (SNI) value to send in the TLS handshake. If unset, the SNI is derived from the destination hostname, which does not match the NGINX server certificate in this example. backend.tls.verifySubjectAltNamesThe Subject Alternative Names (SANs) to verify in the server certificate. If unset, the destination hostname is used, which does not match the NGINX server certificate in this example. Send a request to the NGINX server and verify that you get back a 200 HTTP response code.
- Cloud Provider LoadBalancer
curl -vi http://$INGRESS_GW_ADDRESS:80/ -H "host: example.com:80" - Port-forward for local testing
curl -vi http://localhost:8080/ -H "host: example.com:8080"
Example output:
< HTTP/1.1 200 OK HTTP/1.1 200 OK- Cloud Provider LoadBalancer
Cleanup
You can remove the resources that you created in this guide.In-cluster service
kubectl delete deployment,service,backendtlspolicy,configmap,httproute -A -l app=nginx
kubectl delete secret nginx-server-cert -n agentgateway-system --ignore-not-found
kubectl delete configmap ca -n agentgateway-system --ignore-not-foundRemove the certificates that you created.
cd .. && rm -rf example_certsExternal service
Delete the resources that you created.
kubectl delete httproute httpbin-org -n agentgateway-system
kubectl delete backendtlspolicy httpbin-org -n agentgateway-system
kubectl delete AgentgatewayBackend httpbin-org -n agentgateway-systemCA certificate in a Secret
kubectl delete AgentgatewayPolicy nginx-backend-tls -n agentgateway-system --ignore-not-found
kubectl delete secret nginx-ca -n agentgateway-system --ignore-not-found