NGINX to Istio HTTPS: Configure SNI and Certificate Verification
Posted on July 21, 2020
Updated
When NGINX proxies HTTPS to an Istio gateway, the upstream TLS handshake needs the intended server name and a trusted certificate. The HTTP Host header and TLS SNI serve different layers. Enabling SNI can fix routing, but it does not by itself verify the upstream certificate or secure the client-to-NGINX connection.
Identify the TLS boundaries
Record whether the client connects to NGINX over HTTPS, whether NGINX terminates that connection, and whether the gateway terminates a new TLS connection. Istio SIMPLE gateway TLS is separate from mesh mutual TLS. For end-to-end encryption, every required leg must be configured and tested.
Configure the NGINX upstream deliberately
This server block assumes an upstream gateway on 127.0.0.1:30443, a certificate with DNS SAN app.example.test, and its CA at the specified path. The HTTP listener is for the local upstream test only. Configure an HTTPS client listener for a production path that requires encryption on both legs.
server {
listen 8080;
server_name app.example.test;
location / {
proxy_pass https://127.0.0.1:30443;
proxy_ssl_server_name on;
proxy_ssl_name app.example.test;
proxy_ssl_trusted_certificate /etc/nginx/certs/lab-ca.crt;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_set_header Host app.example.test;
proxy_http_version 1.1;
}
}Use an explicit expected hostname rather than trusting an arbitrary incoming Host header. Validate the configuration with nginx -t before reloading it.
Check the gateway and certificate
Use a supported Istio/Kubernetes combination. The original Istio 1.6.5 installation and addon switches are historical. Current Gateway and VirtualService examples must match the APIs served by your installed Istio. Store the certificate in the gateway’s expected namespace and verify its SAN, expiry, key and chain.
If using a NodePort gateway, select the HTTPS port by name rather than assuming it is the third item in a list. Production load-balancer and Gateway API setups can expose a different address and port.
Test both success and rejection
curl --fail --cacert lab-ca.crt \
--resolve app.example.test:30443:127.0.0.1 \
https://app.example.test:30443/--resolve controls address resolution while the URL hostname supplies the TLS name. A Host header alone does not change SNI. Repeat with an incorrect hostname and an untrusted CA; those requests should fail verification. Inspect NGINX and gateway logs before attributing a 426 or 502 to a particular setting.
The local regression checked NGINX against a disposable TLS upstream. The subsequent live run used Istio 1.30.7 on EKS 1.36.5, with a networking.istio.io/v1 Gateway and VirtualService. Direct HTTPS with the correct SNI and CA succeeded; a wrong hostname was rejected. NGINX then proxied successfully with upstream certificate verification enabled. The test used a ClusterIP gateway and private port forwarding, with no public load balancer.
Sources and further reading
Keep chart versions and namespaces consistent
Use the support matrix and the chart versions actually available from the official repository. The live test used the supported 1.30.7/1.36 combination. A custom control-plane namespace must also be set consistently in the base, istiod and gateway chart values; setting only the release namespace left a reference to the default istio-system namespace and failed installation.
# In the tested disposable cluster; inspect values before installing.
helm repo add istio https://istio-release.storage.googleapis.com/charts
kubectl create namespace mesh-lab
helm upgrade --install istio-base istio/base --version 1.30.7 -n mesh-lab --set global.istioNamespace=mesh-lab --wait
helm upgrade --install istiod istio/istiod --version 1.30.7 -n mesh-lab --set global.istioNamespace=mesh-lab --waitConfigure the gateway’s same namespace setting, its service exposure and the intended selector before applying the TLS Secret, Gateway and VirtualService. This validates an HTTPS ingress leg; mesh mutual TLS and an encrypted client-to-NGINX leg remain separate configuration decisions.