Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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: or DEFAULT, 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.