|
For the latest stable version, please use Korvet 0.19! |
Authentication
This guide covers configuring SASL authentication to secure access to Korvet.
Overview
Korvet supports SASL (Simple Authentication and Security Layer) authentication to control access to the Kafka protocol endpoint. When enabled, clients must authenticate before producing or consuming messages.
Supported Mechanisms
-
SASL/SCRAM-SHA-256 - Challenge-response authentication using stored SCRAM keys. This is the default mechanism.
-
SASL/PLAIN - Username and password authentication. Must be opted in explicitly and requires TLS (see below).
By default, only SCRAM-SHA-256 is advertised to clients. The advertised mechanisms are controlled by korvet.broker.sasl.mechanisms (default SCRAM-SHA-256).
Enabling Authentication
Configuration
Enable SASL authentication in your Korvet configuration:
korvet:
broker:
sasl:
enabled: true
mechanisms:
- SCRAM-SHA-256
Or using environment variables:
KORVET_BROKER_SASL_ENABLED=true
KORVET_BROKER_SASL_MECHANISMS=SCRAM-SHA-256
Enabling PLAIN
PLAIN is not advertised by default. To use it, add it explicitly to korvet.broker.sasl.mechanisms. Because PLAIN transmits credentials without encryption, Korvet requires TLS to be enabled when PLAIN is advertised. Starting the broker with PLAIN advertised while korvet.broker.tls=false fails validation at startup with:
korvet.broker.sasl: PLAIN mechanism requires korvet.broker.tls=true
Clients using PLAIN must therefore connect with the SASL_SSL security protocol, not SASL_PLAINTEXT.
korvet:
broker:
tls: true
sasl:
enabled: true
mechanisms:
- SCRAM-SHA-256
- PLAIN
Managing Credentials
Credential Storage
Credentials are stored in Redis using secure PBKDF2 password hashing:
-
Algorithm: PBKDF2WithHmacSHA256
-
Iterations: 10,000
-
Salt: 128-bit random per credential
-
Hash: 256-bit output
Creating User Credentials
Use the Korvet admin API or Redis CLI to create user credentials. The admin API (see Deployment for enabling it) exposes credential management over HTTP; the Redis CLI approach below is shown for direct access.
Using Redis CLI
# Store a SCRAM-SHA-256 credential for user "alice" in tenant "tenant1"
redis-cli HSET korvet:broker:credentials:alice \
mechanism SCRAM-SHA-256 \
password_hash <base64-encoded-StoredKey> \
server_key <base64-encoded-ServerKey> \
salt <base64-encoded-salt> \
iterations 10000 \
tenant_id tenant1
For SCRAM, password_hash stores the Base64-encoded StoredKey and server_key
stores the Base64-encoded ServerKey. Do not store the salted password.
To create a PLAIN credential (only usable when PLAIN is advertised and TLS
is enabled), use mechanism PLAIN with password_hash, salt, and
iterations fields.
Programmatic Creation
import com.redis.korvet.broker.redis.RedisCredentialStore;
// Create credential store
RedisCredentialStore credentialStore =
new RedisCredentialStore(redisClient, "korvet");
PasswordHasher passwordHasher = new PasswordHasher();
// Hash the password
PasswordHasher.HashedPassword hashed =
passwordHasher.hashPassword("secret-password");
// Store the credential
StoredCredential credential = StoredCredential.builder()
.username("alice")
.mechanism("PLAIN")
.passwordHash(hashed.getHash())
.salt(hashed.getSalt())
.iterations(hashed.getIterations())
.tenantId("tenant1")
.build();
credentialStore.storeCredential(credential);
Updating Credentials
To update a user’s password, store a new credential with the same username:
// Hash new password
PasswordHasher.HashedPassword newHashed =
passwordHasher.hashPassword("new-password");
// Update credential
StoredCredential updated = StoredCredential.builder()
.username("alice")
.mechanism("PLAIN")
.passwordHash(newHashed.getHash())
.salt(newHashed.getSalt())
.iterations(newHashed.getIterations())
.tenantId("tenant1")
.build();
credentialStore.storeCredential(updated);
Client Configuration
Kafka Producer
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
// SASL configuration (default SCRAM-SHA-256 mechanism)
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_PLAINTEXT");
props.put(SaslConfigs.SASL_MECHANISM, "SCRAM-SHA-256");
props.put(SaslConfigs.SASL_JAAS_CONFIG,
"org.apache.kafka.common.security.scram.ScramLoginModule required " +
"username=\"alice\" " +
"password=\"secret-password\";");
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
For PLAIN clients, use the SASL_SSL security protocol (PLAIN requires TLS) and Kafka’s PLAIN login module:
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
props.put(SaslConfigs.SASL_MECHANISM, "PLAIN");
props.put(SaslConfigs.SASL_JAAS_CONFIG,
"org.apache.kafka.common.security.plain.PlainLoginModule required " +
"username=\"alice\" " +
"password=\"secret-password\";");
Kafka Consumer
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "my-group");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
StringDeserializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
StringDeserializer.class.getName());
// SASL configuration (default SCRAM-SHA-256 mechanism)
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_PLAINTEXT");
props.put(SaslConfigs.SASL_MECHANISM, "SCRAM-SHA-256");
props.put(SaslConfigs.SASL_JAAS_CONFIG,
"org.apache.kafka.common.security.scram.ScramLoginModule required " +
"username=\"alice\" " +
"password=\"secret-password\";");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
For PLAIN, set security.protocol=SASL_SSL, sasl.mechanism=PLAIN, and use the PlainLoginModule (PLAIN requires TLS).
Command Line Tools
# kafka-console-producer
kafka-console-producer \
--bootstrap-server localhost:9092 \
--topic test \
--producer-property security.protocol=SASL_PLAINTEXT \
--producer-property sasl.mechanism=SCRAM-SHA-256 \
--producer-property 'sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="alice" password="secret-password";'
# kafka-console-consumer
kafka-console-consumer \
--bootstrap-server localhost:9092 \
--topic test \
--from-beginning \
--consumer-property security.protocol=SASL_PLAINTEXT \
--consumer-property sasl.mechanism=SCRAM-SHA-256 \
--consumer-property 'sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="alice" password="secret-password";'
Multi-Tenancy
Each credential is associated with a tenant ID. When a client authenticates, the tenant ID is attached to the connection and can be used for:
-
Data isolation - Separate topics and consumer groups per tenant
-
Resource quotas - Limit resources per tenant
-
Access control - Restrict access to tenant-specific resources
Tenant Mapping
// User "alice" belongs to "tenant1"
StoredCredential credential = StoredCredential.builder()
.username("alice")
.tenantId("tenant1")
// ... other fields
.build();
// User "bob" belongs to "tenant2"
StoredCredential credential2 = StoredCredential.builder()
.username("bob")
.tenantId("tenant2")
// ... other fields
.build();
Security Best Practices
Password Security
-
Use strong, randomly generated passwords
-
Rotate passwords regularly
-
Never commit passwords to version control
-
Use environment variables or secret management systems
Network Security
SASL/PLAIN transmits credentials in base64 encoding (not encrypted). Korvet therefore requires TLS whenever PLAIN is advertised, so PLAIN clients must use the SASL_SSL security protocol. SCRAM-SHA-256 does not send the password and can be used over SASL_PLAINTEXT, though TLS is still recommended in production:
-
Use TLS - Required for
PLAIN(SASL_SSL); recommended for SCRAM -
Network isolation - Deploy in private networks
-
Firewall rules - Restrict access to Korvet port
Troubleshooting
Authentication Failures
Invalid Credentials
ERROR Authentication failed for user 'alice': Invalid password
Solution: Verify the username and password are correct.
Migration Guide
Enabling Authentication on Existing Deployment
| Enabling authentication will break existing unauthenticated clients. |
-
Create credentials for all existing applications
-
Update client configurations with SASL settings
-
Test authentication with a subset of clients
-
Enable SASL in Korvet configuration
-
Monitor for authentication failures
-
Update remaining clients