mTLS Policies in NGINX Ingress Controller

by

in , ,

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-secret for the CA certificate used to verify client certificates.
  • ingress-mtls-policy for the Policy resource.
  • cafe-ingress for the Ingress resource.
  • cafe for 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?

  1. NGINX Ingress Controller reads ingress-mtls-policy from nginx.org/policies.
  2. The policy supplies the CA certificate and client certificate verification settings.
  3. 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-secret is a valid nginx.org/ca secret in the same namespace as the policy.
  • The Ingress has TLS termination enabled with a valid kubernetes.io/tls secret.
  • The Ingress is not a mergeable minion.
  • verifyClient is set to the appropriate mode (“on”, “off”, “optional”, or “optional_no_ca”).
  • verifyDepth matches 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:

  1. It reads the egressMTLS policy and turns it into upstream TLS settings such as client certificate, trusted CA, verification depth, and SNI options.
  2. It separately determines whether the upstream connection itself should use TLS, based on annotations such as nginx.org/ssl-services or nginx.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-secret for the client certificate and key presented to the upstream.
  • egress-trusted-ca-secret for the CA bundle used to verify the upstream certificate.
  • egress-mtls-policy for the Policy resource.
  • webapp-ingress for the Ingress resource.
  • secure-app for 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?

  1. NGINX Ingress Controller reads egress-mtls-policy from nginx.org/policies.
  2. The policy supplies the client certificate, trusted CA, verification settings, and optional SNI settings.
  3. nginx.org/ssl-services: "secure-app" tells NGINX Ingress Controller to configure that upstream connection over HTTPS.
  4. 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-services for HTTPS upstreams.
  • nginx.org/grpc-services for 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 Ingress or a master Ingress, 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-secret is a valid kubernetes.io/tls secret in the same namespace as the policy.
  • egress-trusted-ca-secret is a valid nginx.org/ca secret in the same namespace as the policy.
  • The backend is listed under nginx.org/ssl-services or nginx.org/grpc-services.
  • verifyServer is enabled if the upstream certificate must be verified.
  • sslName matches 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.

  • VirtualServer can apply egressMTLS at server scope.
  • VirtualServer routes and VirtualServerRoute subroutes 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.

NGINX Community Forum