Integrate third-party Gateway and Ingress controllers
While Istio comes with its own Gateway implementation, which can be used to control ingress and egress traffic, you may already have an alternative implementation in your cluster. This can be integrated into the mesh with a few simple steps.
In this example, you will deploy ingress-nginx. Unless otherwise noted, these steps should apply to any ingress implementation that runs as in-cluster workloads.
Set up the legacy ingress
Using Helm, install the ingress-nginx
chart:
$ helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
Apply a simple routing rule pointing to the service that you wish to expose:
$ kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bookinfo-ingress
spec:
ingressClassName: nginx
defaultBackend:
service:
name: productpage
port:
number: 9080
EOF
In this example, the productpage
deployment is already in the mesh.
If you send requests to the ingress, you will find ztunnel log output that shows a successful connection (some fields are elided):
access connection complete src.workload="ingress-nginx-controller-cbcf8bf58-95vh2" dst.workload="productpage-v1-dffc47f64-gdqdz" direction="inbound"
While the requests work, you can see there is no mutual TLS between ingress-nginx
and productpage
.
Additionally, since only the productpage
pod is in the mesh, you will only see direction="inbound"
logs from it (rather than an additional direction="outbound"
log coming from ingress-nginx
).
Add the ingress into the mesh
In order to get mTLS between the ingress and our workloads, the ingress workload can be added to the ambient mesh – just like any other workload.
$ kubectl label ns ingress-nginx istio.io/dataplane-mode=ambient
With this done, the logs now show mTLS is enabled:
access connection complete src.workload="ingress-nginx-controller-cbcf8bf58-95vh2" src.identity="spiffe://cluster.local/ns/ingress-nginx/sa/ingress-nginx" dst.workload="productpage-v1-dffc47f64-gdqdz" dst.identity="spiffe://cluster.local/ns/default/sa/bookinfo-productpage" direction="outbound"
Note that the log shows a dst.workload
, not a dst.service
. This is because ingress-nginx
does its own internal load balancing and sends traffic to specific Pods, rather than to a Service. While this is fine for many cases, if you have a waypoint attached to the destination service, it will not be used.
Configure the ingress to send to Services (optional)
If you want the ingress to send to Services, rather than Pods, you will need to configure the ingress controller itself. Since this configuration is not part of any standardized API, you will need to consult your ingress provider documentation for more information.
ingress-nginx
supports this model with the nginx.ingress.kubernetes.io/service-upstream
annotation. Add that to your Ingress:
$ kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bookinfo-ingress
annotations:
# NEW: added to tell nginx to send to the service, rather than pod, of the backend.
nginx.ingress.kubernetes.io/service-upstream: "true"
spec:
ingressClassName: nginx
defaultBackend:
service:
name: productpage
port:
number: 9080
EOF
Checking the logs again, you see the requests are now hitting the destination service, as indicate by the dst.service
logs:
access connection complete src.workload="ingress-nginx-controller-cbcf8bf58-95vh2" src.identity="spiffe://cluster.local/ns/ingress-nginx/sa/ingress-nginx" 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"
Implementation-specific configurations
Below is an assortment of implementation-specific configuration to configure sending traffic to Services.
Implementation | Configuration |
---|---|
ingress-nginx | Set the nginx.ingress.kubernetes.io/service-upstream: "true" annotation in the Ingress resources |
Emissary-Ingress | no changes required; sending to Services is the default behavior |
F5 NGINX | Set the use-cluster-ip field in the VirtualServer configuration |
Skip inbound capture (optional)
In step 2, you added the ingress workload to the mesh in order to ensure outbound traffic from the pod was a part of the mesh. However, this additionally captures inbound traffic.
While ztunnel can efficiently handle this traffic, typically there is little value to doing so, especially since ingress workloads are commonly the most performance-sensitive.
Ingress capture can be disabled. This is done by setting the ambient.istio.io/bypass-inbound-capture": "true"
annotation on the ingress controller pods.
When this is enabled, only outbound traffic is captured; any inbound traffic will bypass the mesh.