Allow verify_and_map to derive identity from any certificate attribute, not just email/SAN/DN
Proposed change
verify_and_map currently derives a client's identity from a fixed precedence —
email address, then SAN, then Distinguished Name - and matches the result
literally against a configured user. This proposes making verify_and_map
accept a template string (Go text/template) as an alternative to true:
verify_and_map: "{{ first .OrganizationalUnit }}"The template is executed against the peer certificate's Subject and SAN fields
(CN, O, OU, L, ST, C, SerialNumber, DNS names, emails, IPs, URIs), plus two
helpers for multi-valued attributes: has (membership test) and first
(first value). Fields can be combined with the language's own and/or/eq
to derive an identity from more than one attribute, e.g.:
verify_and_map: '{{if and (has "infra" .OrganizationalUnit) (has "GB" .Country)}}infra-gb{{end}}'This is fully backward compatible: verify_and_map: true/false keep their
exact current behavior unchanged, the template form is opt-in, and a template
referencing a nonexistent field is rejected at config load rather than failing
silently on first connect.
Use case
Today, every distinct client certificate has to be individually enumerated as a configured user, even when a whole group of certificates should share the same access - e.g. any certificate issued to an "infrastructure" OU, or a specific team/service tier. There's no way to grant access by an attribute of the certificate rather than by the certificate's exact identity, which doesn't scale for organisations issuing many individual mTLS certificates (one per service or person) that should nonetheless share a single set of permissions.
Being able to map on OU (or a combination of attributes) lets an operator authorise "anyone with a cert from this OU" once, instead of maintaining a per-certificate user list that has to be updated every time a certificate is issued, rotated, or revoked for an individual within that group.
Contribution
Yes; I have a draft contribution #8392
Source: nats-io/nats-server