Skip to content

Third-party gateways and ingress controllers

Page as Markdown

    

Integrate a third-party in-cluster ingress controller into your ambient mesh to secure traffic between the ingress and backend services with mTLS.

If you already have an in-cluster ingress controller that does not use the Kubernetes Gateway API, you can add it to your ambient mesh to secure traffic between the ingress and your backend services with mTLS.

Warning

Cloud load balancers cannot be added to the mesh using this method.

Before you begin

Deploy your ingress controller and configure it to route traffic to the service you want to expose. Refer to your controller’s documentation for installation and setup.

Add the ingress controller to the mesh

Label the ingress controller’s namespace to add it to the ambient mesh, just like any other workload.

kubectl label ns <ingress-namespace> istio.io/dataplane-mode=ambient

Before labeling the namespace, ztunnel logs show a successful connection but no mutual TLS (some fields are elided):

access  connection complete  src.workload="my-ingress-controller-cbcf8bf58-95vh2" dst.workload="productpage-v1-dffc47f64-gdqdz" direction="inbound"

After labeling the namespace, the logs confirm mTLS is enabled:

access  connection complete  src.workload="my-ingress-controller-cbcf8bf58-95vh2" src.identity="spiffe://cluster.local/ns/ingress-ns/sa/ingress" dst.workload="productpage-v1-dffc47f64-gdqdz" dst.identity="spiffe://cluster.local/ns/default/sa/bookinfo-productpage" direction="outbound"

Note that the log shows dst.workload, not dst.service. Most ingress controllers do their own internal load balancing and send traffic directly to Pods rather than to a Service. If you have a waypoint attached to the destination service, it will not be used unless the ingress is configured to send to Services instead.

Configure the ingress to send to Services (optional)

To ensure waypoint policies are applied, configure your ingress controller to route to Service IPs rather than Pod IPs. Since this is not standardized across controllers, consult your controller’s documentation for the specific configuration.

After making this change, the logs show dst.service instead of dst.workload, confirming traffic is hitting the Service:

access  connection complete  src.workload="my-ingress-controller-cbcf8bf58-95vh2" src.identity="spiffe://cluster.local/ns/ingress-ns/sa/ingress" dst.service="productpage.default.svc.cluster.local" dst.workload="productpage-v1-dffc47f64-gdqdz" dst.identity="spiffe://cluster.local/ns/default/sa/bookinfo-productpage" direction="outbound"

The following table shows implementation-specific configurations for some common controllers.

Implementation Configuration
ingress-nginx (archived)Set the nginx.ingress.kubernetes.io/service-upstream: "true" annotation on Ingress resources
Emissary-IngressNo changes required; sending to Services is the default behavior
F5 NGINXSet the use-cluster-ip field in the VirtualServer configuration

Skip inbound capture (optional)

When you add the ingress namespace to the mesh, ztunnel also intercepts inbound traffic to the ingress workload from external clients. While ztunnel handles this efficiently, external clients may not support mTLS, and ingress workloads are commonly the most performance-sensitive.

To disable mTLS for inbound traffic while keeping mTLS on the backend connections between the ingress and your mesh services, add the ambient.istio.io/bypass-inbound-capture: "true" annotation to the ingress controller pods.

Tip

Only use this annotation if the workload exclusively receives traffic from clients outside the mesh.