KIP-371 — mTLS principal mapping
Status: implemented — see the KIP index.
What the KIP changes in Apache Kafka
KIP-371 (Kafka 2.2) added ssl.principal.mapping.rules: a broker config
that turns an mTLS client certificate's X.500 subject DN into a short
principal name without writing a custom PrincipalBuilder class. Rules
are a comma-separated list of RULE:<regex>/<replacement>/[L|U] entries
plus DEFAULT; the first matching rule wins. It mirrors what
sasl.kerberos.principal.to.local.rules already did for Kerberos names.
How kaas implements it
crates/kaas-auth/src/principal_mapping.rs parses Apache's rule syntax:
RULE:<regex>/<replacement>/with$1,$2, … back-references into the regex's capture groups, matched against the full subject DN.- Optional
/L(lowercase) or/U(uppercase) postfix on the result. - First matching rule wins; commas inside a regex body are handled — the
spec is split only at commas immediately followed by
RULE:orDEFAULT, because subject DNs use commas as their own separator.
The rules arrive via the KAAS_SSL_PRINCIPAL_MAPPING_RULES env
(crates/kaas-broker/src/cli.rs) and are compiled once at startup in
bins/kaas/src/main.rs — a parse error (bad syntax, invalid regex)
fails boot rather than silently mapping every certificate to its CN,
so a chart-config typo is loud. The compiled mapper is wired into the
accept path in crates/kaas-protocol/src/server.rs; after the TLS
handshake, crates/kaas-auth/src/mtls.rs extracts the leaf certificate's
subject DN, applies the mapper, and authenticates the mapped name against
the credentials store. The resulting principal is what the cluster-wide
authorizer and quota checker see.
One deliberate deviation: in Apache, DEFAULT (and the no-match
fall-through) yields the full DN string as the principal. In kaas both
return the certificate's CN (principal_mapping.rs, Rule::Default
and the fall-through in apply), and an empty rule spec behaves the same.
That matches how kaas keys credentials.json entries — operator-managed
KafkaUser names, not DN strings — and preserves the pre-mapping
behaviour for clusters that never set the env. If you need Apache's
DN-shaped principals, an explicit RULE:^(.*)$/$1/ reproduces them.
How it's verified
Unit tests in crates/kaas-auth/src/principal_mapping.rs:
first_rule_wins_with_back_reference, lower_case_flag_applied,
upper_case_flag_applied, split_rules_keeps_dn_commas_inside_regex
(the comma-in-DN parser edge), multiple_rules_first_match_wins,
unmatched_rule_falls_through_to_cn, empty_spec_returns_cn, and the
fail-fast pair invalid_rule_syntax_errors / invalid_regex_errors.
The DN-extraction + mapper + engine composition is covered in
crates/kaas-auth/src/mtls.rs's tests. There is no shell-suite mTLS
scenario — the Apache CLI tools in scripts/ bootstrap over the
anonymous or SCRAM listeners.