The NSI Authentication Server (nsi-auth) is designed to integrate with
Kubernetes ingress controllers such as ingress-nginx and Traefik.
When an authentication request is sent to nsi-auth, the server extracts the
client certificate’s Distinguished Name (DN) from an HTTP header and
verifies it against the list of allowed DNs using standards-compliant
RFC 4514 comparison (via Python cryptography x509.Name objects).
Depending on the ingress controller, the DN can be extracted from:
- A DN string header (
ssl-client-subject-dn) — used by ingress-nginx - A PEM certificate or certificate chain (
X-Forwarded-Tls-Client-Cert) — used by Traefik - A certificate info summary (
X-Forwarded-Tls-Client-Cert-Info) — used by Traefik
The header to use is selected via configuration (see Configuration Options).
- ✅ If the DN is authorized, the server responds with HTTP 200 (OK) and returns
X-Auth-Method: mTLSandX-Client-DN: <RFC 4514 DN>response headers - ❌ If not authorized, it returns HTTP 403 (Forbidden)
The response headers allow downstream services (e.g. nsi-dds-proxy) to verify that mTLS authentication occurred and identify the client. The ingress controller forwards these headers to the upstream application via auth-response-headers (nginx) or authResponseHeaders (Traefik).
nsi-auth is deployed via a Helm chart. The full list of configuration options
can be found in chart/values.yaml.
Below is an example configuration snippet:
image:
repository: ghcr.io/workfloworchestrator/nsi-auth
pullPolicy: IfNotPresent
tag: "latest"
service:
type: ClusterIP
port: 80
targetPort: 8000
volumes:
- name: config
configMap:
name: nsi-auth-config
optional: false
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
livenessProbe:
httpGet:
path: /health
port: http
readinessProbe:
httpGet:
path: /health
port: http
env:
ALLOWED_CLIENT_SUBJECT_DN_PATH: "/config/allowed_client_dn.txt"
TLS_CLIENT_SUBJECT_AUTHN_HEADER: "ssl-client-subject-dn"
USE_WATCHDOG: "False"
LOG_LEVEL: "INFO"
config:
inlineData: |-
allowed_client_dn.txt: |-
CN=CertA,OU=Dept X,O=Company 1,C=NL
CN=CertB,OU=Dept Y,O=Company 2,C=NL
CN=CertC,OU=Dept Z,O=Company 3,C=NL
additionalTrustedCA: ""You can override default values by passing a custom values file:
helm upgrade --install --values my-values.yaml nsi-auth chartNote:
The value
configMap.nameis defined as{{ .Release.Name }}-configand must match your Helm release name. In this example, the release name is nsi-auth.
Alternatively, install directly from the nsi-node Helm repository:
helm repo add nsi-node https://bandwidthondemand.github.io/nsi-node/
helm repo update
helm upgrade --install --values my-values.yaml nsi-auth nsi-node/nsi-authDuring installation, a Kubernetes secret named {{ .Release.Name }}-ca is
automatically created. This secret contains a ca.crt file, which includes:
- The list of CA certificates maintained by cURL
- Any additional certificates defined under
config.additionalTrustedCA
This allows you to extend the trusted CA list with other certificates, including self-signed CAs if needed.
The ca.crt secret is then used by the ingress controller to establish the
trusted CA chain (see Ingress Configuration).
| Variable | Description | Default |
|---|---|---|
ALLOWED_CLIENT_SUBJECT_DN_PATH |
Path to the file listing allowed client certificate DNs. DNs should be as close to RFC 4514 format as possible, stored as UTF-8. | /config/allowed_client_dn.txt |
TLS_CLIENT_SUBJECT_AUTHN_HEADER |
HTTP header used to extract the client identity. Determines ingress mode: ssl-client-subject-dn (ingress-nginx, DN in RFC 2253), X-Forwarded-Tls-Client-Cert (Traefik, PEM certificate or comma-separated chain), or X-Forwarded-Tls-Client-Cert-Info (Traefik, URL-encoded cert info summary). |
ssl-client-subject-dn |
USE_WATCHDOG |
Enables file-change monitoring using watchdog. Useful for non-Kubernetes environments. | False |
LOG_LEVEL |
Logging verbosity. Options: DEBUG, INFO, WARNING, ERROR. |
INFO |
Health endpoint:
nsi-auth exposes a /health endpoint that returns HTTP 200. This is used
for Kubernetes liveness and readiness probes, which are enabled by default in
the Helm chart:
livenessProbe:
httpGet:
path: /health
port: http
readinessProbe:
httpGet:
path: /health
port: httpFile reload behavior:
By default, nsi-auth uses a simple polling mechanism (every 5 seconds) to
detect changes to the DN file. If USE_WATCHDOG is enabled, the watchdog
module provides faster, event-based file monitoring.
⚠️ Note:watchdogcannot be used when running in Kubernetes, because ConfigMap updates replace the file via symbolic links, and this is not detected.
DN format and comparison:
DNs are parsed per RFC 4514 (via cryptography.x509.Name) and compared as
the multiset of (attribute-OID, value) pairs.
This makes matching independent of:
- RDN ordering —
CN=Foo,O=Acme,C=NLandC=NL,O=Acme,CN=Fooare treated as the same identity. - Attribute-type spelling — friendly names and dotted OIDs match each
other (
emailAddress=≡1.2.840.113549.1.9.1=,GN=≡2.5.4.42=,SN=≡2.5.4.4=,organizationIdentifier=≡2.5.4.97=). This is important because different reverse proxies serialize the same DN differently (e.g. Go'scert.Subject.String()falls back to dotted OIDs for any attribute type it doesn't have a friendly name for).
DNs in the allowed DN file should be as close to
RFC 4514 format as possible
(e.g. CN=CertA,OU=Dept X,O=Company 1,C=NL). The file must be UTF-8
encoded.
Finally, configure the ingress controller of the application to:
- Use the
ca.crtsecret created bynsi-auth - Enable and verify mutual TLS (mTLS) authentication
- Forward the client certificate DN (or certificate) to
nsi-authfor validation
Set TLS_CLIENT_SUBJECT_AUTHN_HEADER to ssl-client-subject-dn (the default).
Assuming nsi-auth is deployed in the production namespace, use the
following ingress annotations:
nginx.ingress.kubernetes.io/auth-tls-secret: production/nsi-auth-ca
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
nginx.ingress.kubernetes.io/auth-tls-verify-depth: "3"
nginx.ingress.kubernetes.io/auth-url: http://nsi-auth.production.svc.cluster.local/validateSet TLS_CLIENT_SUBJECT_AUTHN_HEADER to X-Forwarded-Tls-Client-Cert to
have Traefik forward the full PEM certificate (or certificate chain). Configure
the Traefik
PassTLSClientCert
middleware with pem: true:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: nsi-auth-mtls
spec:
passTLSClientCert:
pem: trueAlternatively, set TLS_CLIENT_SUBJECT_AUTHN_HEADER to
X-Forwarded-Tls-Client-Cert-Info to use the Traefik cert info summary header
instead (requires configuring the info.subject fields in the middleware).
These settings ensure that the ingress controller:
- Validates client certificates against the trusted CA chain
- Delegates authorization to the nsi-auth service
📄 License
This project is licensed under the Apache License, Version 2.0.
🧠 See Also