SASL-механизмы
Этот урок — deep-dive в каждый SASL-механизм: как он работает изнутри, как настраивается на брокере и клиенте, каковы его ограничения и когда он подходит. Все примеры используют SASL_SSL (SASL + TLS шифрование) — production standard.
JAAS: основа SASL-конфигурации
JAAS (Java Authentication and Authorization Service) — стандартный Java-механизм, через который Kafka настраивает SASL. Для каждого механизма нужен JAAS-конфиг: какой LoginModule использовать и с какими параметрами.
Два способа передать JAAS-конфиг:
Способ 1: Inline в server.properties (предпочтительный)
listener.name.sasl_ssl.plain.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \
username="admin" password="admin-secret" \
user_admin="admin-secret";
Способ 2: Отдельный файл (устаревший)
# Запуск с указанием файла
KAFKA_OPTS="-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf" \
kafka-server-start.sh server.properties
Inline конфиг предпочтительнее: нет дополнительного файла, проще управлять через ConfigMaps в Kubernetes, изменения видны в одном месте.
SASL/PLAIN
SASL/PLAIN передаёт username и password в base64-кодировке. Это не шифрование: base64 тривиально декодируется. Без SSL это эквивалент отправки пароля открытым текстом.
SASL/PLAIN передаёт логин и пароль как есть (base64, не шифрование). БЕЗ SSL это эквивалент отправки пароля открытым текстом по сети. Всегда комбинируйте SASL/PLAIN с SSL encryption (security.protocol=SASL_SSL).
Broker config: SASL/PLAIN
# Включить PLAIN механизм для SASL_SSL listener
listener.name.sasl_ssl.sasl.enabled.mechanisms=PLAIN
# JAAS config: статические credentials
# user_<name>="<password>" определяет каждого допустимого пользователя
listener.name.sasl_ssl.plain.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \
username="admin" password="admin-secret" \
user_admin="admin-secret" \
user_producer="producer-secret" \
user_consumer="consumer-secret" \
user_monitoring="monitoring-secret";
Добавление нового пользователя (user_newapp="newapp-secret") требует изменения конфига и перезапуска брокера. Это главное ограничение PLAIN.
Client config: SASL/PLAIN
security.protocol=SASL_SSL
sasl.mechanism=PLAIN
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \
username="producer" \
password="producer-secret";
# SSL для шифрования канала
ssl.truststore.location=/etc/kafka/ssl/client.truststore.jks
ssl.truststore.password=truststore-password
Ограничения PLAIN
- Credentials в plaintext в конфиг-файле брокера.
- Ротация пароля = изменение конфига + перезапуск брокера.
- Нет динамического управления пользователями.
Вывод: SASL/PLAIN подходит только для dev/test окружений или очень маленьких кластеров с редкими изменениями пользователей.
SASL/SCRAM-SHA-256 и SCRAM-SHA-512
SCRAM (Salted Challenge-Response Authentication Mechanism) — стандарт RFC 5802. Ключевые свойства:
- Пароль не передаётся по сети — только salted hash challenge/response.
- Credentials хранятся в KRaft metadata log (в Kafka 4.0) в виде salted hash — не plaintext.
- Динамическое управление: добавление/удаление пользователей через
kafka-configs.shбез перезапуска брокера.
SCRAM-SHA-256/512 — оптимальный выбор для большинства production-кластеров: salted challenge-response (пароль не передаётся по сети), динамическое управление credentials без перезапуска, хранение в KRaft metadata.
Управление пользователями
# Создать пользователя alice (SCRAM-SHA-256)
kafka-configs.sh --bootstrap-server localhost:9092 \
--command-config admin.properties \
--alter \
--add-config 'SCRAM-SHA-256=[iterations=8192,password=alice-secret]' \
--entity-type users --entity-name alice
# Создать пользователя с обоими алгоритмами (для обратной совместимости)
kafka-configs.sh --bootstrap-server localhost:9092 \
--command-config admin.properties \
--alter \
--add-config 'SCRAM-SHA-256=[iterations=8192,password=alice-secret],SCRAM-SHA-512=[iterations=8192,password=alice-secret]' \
--entity-type users --entity-name alice
# Список пользователей
kafka-configs.sh --bootstrap-server localhost:9092 \
--command-config admin.properties \
--describe --entity-type users
# Удалить пользователя alice
kafka-configs.sh --bootstrap-server localhost:9092 \
--command-config admin.properties \
--alter \
--delete-config 'SCRAM-SHA-256,SCRAM-SHA-512' \
--entity-type users --entity-name alice
В Kafka 4.0 credentials хранятся в __cluster_metadata internal topic (KRaft log). В Kafka 2.x/3.x они хранились в ZooKeeper — это deprecated и удалено в 4.0.
Broker config: SASL/SCRAM
# Включить SCRAM-SHA-256 механизм
listener.name.sasl_ssl.sasl.enabled.mechanisms=SCRAM-SHA-256
# JAAS: ScramLoginModule делегирует в KRaft metadata store
# username/password в JAAS — это credential для самого брокера (inter-broker auth)
listener.name.sasl_ssl.scram-sha-256.sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required \
username="kafka-broker" \
password="broker-secret";
# Inter-broker protocol
security.inter.broker.protocol=SASL_SSL
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
Client config: SASL/SCRAM
security.protocol=SASL_SSL
sasl.mechanism=SCRAM-SHA-256
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required \
username="alice" \
password="alice-secret";
ssl.truststore.location=/etc/kafka/ssl/client.truststore.jks
ssl.truststore.password=truststore-password
SCRAM-SHA-256 vs SCRAM-SHA-512
SCRAM-SHA-512 использует SHA-512 вместо SHA-256 — немного сильнее, но незначительно медленнее при handshake (разница измеряется миллисекундами). SHA-256 достаточен для большинства случаев. SHA-512 предпочтителен в высокочувствительных средах (финансы, здравоохранение).
SASL/OAUTHBEARER
OAUTHBEARER интегрирует Kafka с системами управления идентичностью через JWT (JSON Web Token). Клиент получает токен от Identity Provider, предъявляет его брокеру. Брокер валидирует подпись токена через JWKS endpoint (без обращения к IdP при каждом запросе).
Kafka 4.0 включает полноценные встроенные обработчики:
OAuthBearerLoginCallbackHandler: для клиента — получает токен черезgrant_type=client_credentials.OAuthBearerValidatorCallbackHandler: для брокера — валидирует JWT через JWKS.
Broker config: SASL/OAUTHBEARER
# Включить OAUTHBEARER механизм
listener.name.sasl_ssl.sasl.enabled.mechanisms=OAUTHBEARER
# Broker: JAAS (минимальный — фактически конфиг через отдельные ключи)
listener.name.sasl_ssl.oauthbearer.sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required;
# Брокер получает токен для inter-broker auth
listener.name.sasl_ssl.oauthbearer.sasl.login.callback.handler.class=org.apache.kafka.common.security.oauthbearer.secured.OAuthBearerLoginCallbackHandler
# Брокер валидирует клиентские токены
listener.name.sasl_ssl.oauthbearer.sasl.server.callback.handler.class=org.apache.kafka.common.security.oauthbearer.secured.OAuthBearerValidatorCallbackHandler
# JWKS endpoint для валидации подписи JWT
sasl.oauthbearer.jwks.endpoint.url=https://keycloak.example.com/realms/kafka/protocol/openid-connect/certs
# Token endpoint для получения токена (inter-broker)
sasl.oauthbearer.token.endpoint.url=https://keycloak.example.com/realms/kafka/protocol/openid-connect/token
# Ожидаемый audience в JWT (защита от token confusion attacks)
sasl.oauthbearer.expected.audience=kafka-broker
Client config: SASL/OAUTHBEARER
security.protocol=SASL_SSL
sasl.mechanism=OAUTHBEARER
sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required \
clientId="kafka-producer-app" \
clientSecret="client-secret-value" \
scope="kafka:read kafka:write";
sasl.login.callback.handler.class=org.apache.kafka.common.security.oauthbearer.secured.OAuthBearerLoginCallbackHandler
sasl.oauthbearer.token.endpoint.url=https://keycloak.example.com/realms/kafka/protocol/openid-connect/token
ssl.truststore.location=/etc/kafka/ssl/client.truststore.jks
ssl.truststore.password=truststore-password
Интеграция с IdP
OAUTHBEARER работает с любым OAuth 2.0 / OIDC-совместимым IdP:
- Keycloak (open source, on-prem): создайте Realm, Client с
client_credentialsgrant, настройте audience mapper. - Auth0: Applications → Machine-to-Machine, настройте API с аудиторией
kafka-broker. - Azure AD (Entra ID): App Registration, Client Secret, настройте
audclaim. - Google Identity Platform: Service Account с JWT.
Ключевое преимущество: централизованное управление identity. Отзыв доступа у сервиса = отзыв client credentials в IdP. Токены короткоживущие (обычно 5-60 минут) — автоматически обновляются Kafka client library.
Маппинг JWT claim в Kafka principal:
# Какой claim JWT использовать как principal (default: sub)
sasl.oauthbearer.sub.claim.name=preferred_username
SASL/GSSAPI (Kerberos)
GSSAPI (Generic Security Services API) в контексте Kafka означает Kerberos. Это enterprise SSO через Active Directory или MIT Kerberos. Клиент аутентифицируется в KDC (Key Distribution Center) и получает Service Ticket для Kafka.
Как работает Kerberos authentication
- Клиент аутентифицируется в KDC через keytab файл → получает TGT (Ticket Granting Ticket).
- Клиент запрашивает Service Ticket у KDC для Kafka service (
kafka/broker.example.com@REALM). - Клиент предъявляет Service Ticket Kafka-брокеру.
- Брокер верифицирует Service Ticket через свой keytab — без обращения к KDC при каждом запросе.
Broker config: SASL/GSSAPI
# Включить GSSAPI механизм
listener.name.sasl_ssl.sasl.enabled.mechanisms=GSSAPI
# Kerberos service name (используется для формирования SPN: kafka/broker.example.com@REALM)
sasl.kerberos.service.name=kafka
# Broker JAAS: Krb5LoginModule с keytab
listener.name.sasl_ssl.gssapi.sasl.jaas.config=com.sun.security.auth.module.Krb5LoginModule required \
useKeyTab=true \
storeKey=true \
keyTab="/etc/kafka/kafka.service.keytab" \
principal="kafka/[email protected]";
Дополнительно: JVM должна знать расположение krb5.conf:
# В KAFKA_OPTS или kafka-server-start.sh
export KAFKA_OPTS="-Djava.security.krb5.conf=/etc/krb5.conf"
Client config: SASL/GSSAPI
security.protocol=SASL_SSL
sasl.mechanism=GSSAPI
sasl.kerberos.service.name=kafka
sasl.jaas.config=com.sun.security.auth.module.Krb5LoginModule required \
useKeyTab=true \
storeKey=true \
keyTab="/etc/kafka/alice.keytab" \
principal="[email protected]";
Практические сложности GSSAPI:
- Требуется рабочий KDC, настроенный realm, keytab файлы для каждого сервиса.
krb5.confдолжен быть синхронизирован на всех машинах.- Системное время: Kerberos требует синхронизацию времени в пределах 5 минут (NTP обязателен).
- Отладка через
KRB5_TRACE=/dev/stderrили Kerberos log.
Вывод: SASL/GSSAPI выбирают, когда организация уже использует Active Directory/MIT Kerberos и требует SSO интеграцию. В облачных средах OAUTHBEARER обычно предпочтительнее.
Несколько механизмов на одном listener
Kafka поддерживает несколько активных SASL-механизмов одновременно на одном listener. Клиент выбирает механизм через sasl.mechanism.
# Broker: два механизма активны
listener.name.sasl_ssl.sasl.enabled.mechanisms=SCRAM-SHA-256,OAUTHBEARER
# Конфигурация для каждого механизма отдельно
listener.name.sasl_ssl.scram-sha-256.sasl.jaas.config=...
listener.name.sasl_ssl.oauthbearer.sasl.jaas.config=...
# Inter-broker: фиксированный механизм (выбирает один)
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
Это позволяет поддерживать смешанную среду: старые сервисы на SCRAM, новые — на OAUTHBEARER.
Миграция с PLAIN на SCRAM без downtime
Поэтапная миграция с SASL/PLAIN на SASL/SCRAM без остановки кластера:
Шаг 1: Добавить SCRAM к активным механизмам (PLAIN остаётся):
listener.name.sasl_ssl.sasl.enabled.mechanisms=PLAIN,SCRAM-SHA-256
Перезапустите брокеры по одному (rolling restart).
Шаг 2: Создать SCRAM credentials для всех существующих пользователей:
kafka-configs.sh --alter --add-config 'SCRAM-SHA-256=[...]' --entity-type users --entity-name producer
kafka-configs.sh --alter --add-config 'SCRAM-SHA-256=[...]' --entity-type users --entity-name consumer
Шаг 3: Мигрировать клиентов по одному на sasl.mechanism=SCRAM-SHA-256. Каждый клиент мигрирует независимо — оба механизма активны, клиенты в любом порядке переключаются.
Шаг 4: Когда все клиенты мигрированы, убрать PLAIN из enabled mechanisms:
listener.name.sasl_ssl.sasl.enabled.mechanisms=SCRAM-SHA-256
Rolling restart. Миграция завершена без единой секунды downtime.
Ключевые выводы
- JAAS config — основа SASL. Inline в
server.propertiesпредпочтительнее отдельного файла. - PLAIN: статические credentials в JAAS config, ротация = перезапуск. Только с SSL. Только dev.
- SCRAM: salted challenge-response, credentials в KRaft metadata, динамическое управление без перезапуска. Production default.
- OAUTHBEARER: JWT от внешнего IdP. Централизованное управление identity, короткоживущие токены. Cloud-native.
- GSSAPI: Kerberos enterprise SSO. Самый сложный. Только при наличии KDC инфраструктуры.
- Несколько механизмов на listener — для плавной миграции между механизмами.