NGINX Ingress Controller 5.5 brings full support for mTLS in Ingress objects! This blog post gives a more in-depth overview of our GitHub deployment examples and shows how to configure both our new ingress and egress mTLS Policy CRDs in NGINX Ingress Controller using annotations.
Ingress mTLS
Ingress mTLS configures how NGINX verifies client certificates on an incoming HTTPS connection. The policy generates the server-level client certificate directives (CA certificate, verify mode, and verify depth) for the host that references it.
The example in our GitHub repo uses these resources:
ingress-mtls-secretfor the CA certificate used to verify client certificates.ingress-mtls-policyfor the Policy resource.cafe-ingressfor the Ingress resource.cafefor the cafe application.
The policy resource is:
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: ingress-mtls-policy
spec:
ingressMTLS:
clientCertSecret: ingress-mtls-secret
verifyClient: "on"
verifyDepth: 1
This configures NGINX to:
- Require a client certificate from connecting clients.
- Verify the client certificate against the CA in ingress-mtls-secret.
- Allow a certificate chain depth of up to 1.
The Ingress resource is:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/policies: "ingress-mtls-policy"
spec:
ingressClassName: nginx
tls:
- hosts:
- cafe.example.com
secretName: tls-secret
rules:
- host: cafe.example.com
http:
paths:
- path: /tea
pathType: Prefix
backend:
service:
name: tea-svc
port:
number: 80
- path: /coffee
pathType: Prefix
backend:
service:
name: coffee-svc
port:
number: 80
How Does it Work?
- NGINX Ingress Controller reads
ingress-mtls-policyfromnginx.org/policies. - The policy supplies the CA certificate and client certificate verification settings.
- NGINX Ingress Controller renders the server-level client certificate directives in the generated NGINX configuration.
What Does the Policy Not Do
ingressMTLS does not enable TLS termination by itself.
It only configures the client certificate verification parameters that NGINX should use after TLS termination is already active on the host.
For Ingress, the host must have TLS termination configured with a valid kubernetes.io/tls secret.
Without that, NGINX Ingress Controller will reject the policy with a warning and serve 500 for all requests to that host.
Mergeable Ingress Behavior
ingressMTLS is not supported on mergeable minions. A minion Ingress that references an ingressMTLS policy will be rejected and NGINX will serve 500 for requests handled by that minion.
Checks Before Rollout
Verify these points:
ingress-mtls-secretis a validnginx.org/casecret in the same namespace as the policy.- The
Ingresshas TLS termination enabled with a validkubernetes.io/tlssecret. - The
Ingressis not a mergeable minion. verifyClientis set to the appropriate mode (“on”, “off”, “optional”, or “optional_no_ca”).verifyDepthmatches the depth of your client certificate chain.- Requests fail with 400 No required SSL certificate was sent when no client certificate is presented.
Also Available for VirtualServer
The same ingressMTLS policy type is also available for VirtualServer.
- VirtualServer can apply ingressMTLS at server scope via the spec field.
- VirtualServer routes and VirtualServerRoute subroutes cannot apply ingressMTLS.
For VirtualServer, TLS termination is handled by the spec.tls field on the VirtualServer resource. The policy still supplies the CA certificate and verification settings.
Egress mTLS
Egress mTLS configures how NGINX should authenticate to a TLS upstream and how it should verify the upstream certificate.
For Ingress resources, NGINX Ingress Controller does two separate things:
- It reads the
egressMTLSpolicy and turns it into upstream TLS settings such as client certificate, trusted CA, verification depth, and SNI options. - It separately determines whether the upstream connection itself should use TLS, based on annotations such as
nginx.org/ssl-servicesornginx.org/grpc-services.
That separation is important. The policy does not enable upstream TLS by itself. It only defines how TLS should be used once the upstream connection is already configured to use TLS.
The example in our GitHub repo uses these resources:
egress-mtls-secretfor the client certificate and key presented to the upstream.egress-trusted-ca-secretfor the CA bundle used to verify the upstream certificate.egress-mtls-policyfor thePolicyresource.webapp-ingressfor theIngressresource.secure-appfor the HTTPS backend service.
The policy resource is:
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: egress-mtls-policy
spec:
egressMTLS:
tlsSecret: egress-mtls-secret
trustedCertSecret: egress-trusted-ca-secret
verifyServer: on
verifyDepth: 2
serverName: on
sslName: secure-app.example.com
This configures NGINX to:
- Authenticate to the upstream with the client certificate in
egress-mtls-secret. - Verify the upstream server certificate against
egress-trusted-ca-secret. - Send SNI to the upstream.
- Verify the upstream certificate against
secure-app.example.com.
The Ingress resource is:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
annotations:
nginx.org/policies: egress-mtls-policy
nginx.org/ssl-services: "secure-app"
spec:
ingressClassName: nginx
rules:
- host: webapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-app
port:
number: 8443
How Does it Work?
- NGINX Ingress Controller reads
egress-mtls-policyfromnginx.org/policies. - The policy supplies the client certificate, trusted CA, verification settings, and optional SNI settings.
nginx.org/ssl-services: "secure-app"tells NGINX Ingress Controller to configure that upstream connection over HTTPS.- NGINX Ingress Controller renders the upstream TLS directives for that backend in the generated NGINX configuration.
What Does the Policy Not Do
egressMTLS does not enable upstream TLS by itself.
It only configures the TLS parameters that NGINX should use after the upstream connection is already TLS-enabled.
For Ingress, upstream TLS still needs to be enabled separately:
nginx.org/ssl-servicesfor HTTPS upstreams.nginx.org/grpc-servicesfor gRPC upstreams.
Without that, NGINX still has egress mTLS settings available, but there is no TLS connection for those settings to apply to.
Mergeable Ingress Behavior
egressMTLS is supported on mergeable minions.
The behavior is:
- On a standard
Ingressor a masterIngress, the policy is applied at server scope. - On a minion
Ingress, the policy is applied at location scope. - This allows a minion to override the master’s egress mTLS settings for its own paths.
Checks Before Rollout
Verify these points:
egress-mtls-secretis a validkubernetes.io/tlssecret in the same namespace as the policy.egress-trusted-ca-secretis a validnginx.org/casecret in the same namespace as the policy.- The backend is listed under
nginx.org/ssl-servicesornginx.org/grpc-services. verifyServeris enabled if the upstream certificate must be verified.sslNamematches the hostname expected by the upstream certificate.- Requests fail in the expected way if the trusted CA or client certificate is wrong.
Also Available for VirtualServer and VirtualServerRoute
The same egressMTLS policy type is also available for VirtualServer and VirtualServerRoute.
VirtualServercan applyegressMTLSat server scope.VirtualServerroutes andVirtualServerRoutesubroutes can apply it at location scope.- More specific route-level policy overrides broader policy of the same type.
For VirtualServer and VirtualServerRoute, upstream TLS enablement is handled by the resource fields for upstream TLS. The policy still supplies the certificate, trust, and verification settings.


