Search before asking
Description
Users should be able to configure the SASL authentication options in the Helm chart values.
Willingness to contribute
Update: 02/03/2026
Apache Fluss Helm SASL Support Redesign
This document proposes a redesign for configuring SASL (Simple Authentication and Security Layer) support for Apache Fluss, specifically targeting improvements in user experience and Helm chart maintainability.
Kafka Way of Configuration
The existing method for configuring security, as commonly seen in Kafka deployments, is scattered and unintuitive, requiring configuration across multiple top-level blocks.
Current Configuration Structure
listeners:
client:
protocol:
internal:
protocol:
sasl:
clientMechanism:
interbrokerMechanism:
client:
users:
passwords:
internal:
user:
password:
Drawbacks
- Fragmentation: Users must configure listener protocols under
listeners: and related security details (like users/passwords or TLS settings) under separate, global sasl: or tls: blocks.
- Complexity: The implicit dependency between the listener protocol and the required security block is not clear from the configuration structure alone.
Our Current Approach in Development
An attempt was made to simplify configuration by embedding security details directly under the listener definitions, based on simplification of existing charts (e.g., Bitnami).
Current Configuration Structure (Example)
listeners:
internal:
protocol: PLAINTEXT
port: 9123
security:
mechanism: PLAIN
users: []
client:
protocol: PLAINTEXT
port: 9124
security:
mechanism: PLAIN
users: []
Drawbacks of this Approach
- Inadequate for Advanced Mechanisms: This approach fails when introducing security features that require global configuration or do not fit the user/password model:
- Global configuration (e.g., a shared
tls: block for certificates) would still be necessary outside the listener definitions, reintroducing fragmentation.
- Mechanisms like OAuthBearer do not require a
users block but need unique configuration (e.g., tokenEndpointUrl).
The Helm helpers became heavy during the implementation of this approach and that the values to be input by the user are "not guided" as they could be.
For example:
If you specify SASL protocol, then you need to fill this block
The following redesign aims at being self-explanatory.
Proposed Redesign
The proposed redesign centralizes all security-related settings under a top-level security: block, separating connection details (ports) from authentication/encryption details.
Initial Proposed Configuration Structure
listeners:
client:
port:
internal:
port:
security:
tls: {} # Global TLS settings (e.g., truststores, keystores)
# Security configuration for the client listener
client:
enableTLS: false
sasl:
plain:
enable: false
users: []
scram:
enable: false
sha: 256
users: []
oauth:
enable: false
tokenEndpointUrl:
subClaimName: "sub"
# Security configuration for the internal listener
internal:
enableTLS: false
sasl:
plain:
enable: false
user: ""
password: ""
scram:
enable: false
sha: 256
user: ""
password: ""
oauth:
enable: false
tokenEndpointUrl:
subClaimName: "sub"
This initial approach makes the intent explicit (“I want client SCRAM over TLS”) and lets the chart derive listener protocols and broker config, instead of forcing users to understand all the cross-couplings.
Advantages of initial redesign
-
Single place to reason about security: Users choose the authentication method in one obvious block per listener role (client vs internal).
-
Chart can derive protocol: SASL_PLAINTEXT / SASL_SSL / SSL / PLAINTEXT becomes computed logic rather than user-filled strings.
-
Extensible to new mechanisms (OAuth, future): add a new sub-block without changing listener definitions.
That said, there are a couple design traps worth avoiding so this stays extensible when you add TLS variants, OAuth, mTLS, multiple listeners.
Fixes to the proposed initial redesign
Mutual exclusivity and flags sprawl
With plain.enable, scram.enable, oauth.enable, we are encoding a “one-of” choice as multiple booleans. That tends to break over time:
- What happens if a user enables
plain and scram accidentally?
- What’s the precedence?
- How do you validate it in Helm templates?
We can make it a single choice:
security:
client:
tls:
enabled: false
sasl: # none | plain | scram | oauthbearer
mechanism: none
plain:
users: []
scram:
sha:
users: []
oauth:
tokenEndpointUrl: ""
subClaimName: "sub"
Then the chart:
- validates that the mechanism is one of the allowed values
- reads only the corresponding config section
With this the selection is a single field, and there are separate blocks for each mechanism.
TLS is both global and per listener
The TLS block could be global and per listener:
- Global TLS material: secrets, cert paths, CA bundle, auto-generation options
- Per-listener: whether TLS is required, client auth (mTLS), allowed ciphers, etc.
Adding tls: per listener:
security:
tls:
# material and common knobs
existingSecret: ""
certFileKey: "tls.crt"
keyFileKey: "tls.key"
caFileKey: "ca.crt"
client:
tls:
enabled: false
clientAuth: "none" # none | required
internal:
tls:
enabled: false
clientAuth: "required"
This avoids the future complexity where you might need different TLS policies for internal vs client, but still reuse the same secret.
Final Proposed Values Structure
listeners:
client:
port:
internal:
port:
security:
tls:
# material and common knobs
existingSecret: ""
certFileKey: "tls.crt"
keyFileKey: "tls.key"
caFileKey: "ca.crt"
client:
tls:
enabled: false
clientAuth: "none" # none | required
sasl: # none | plain | scram | oauthbearer
mechanism: none
plain:
users: []
scram:
sha:
users: []
oauth:
tokenEndpointUrl: ""
subClaimName: "sub"
internal:
tls:
enabled: false
clientAuth: "required"
sasl: # none | plain | scram | oauthbearer
mechanism: none
plain:
username: ""
password: ""
scram:
sha:
username: ""
password: ""
oauth:
tokenEndpointUrl: ""
subClaimName: "sub"
Key Benefits
- User Experience: Users interact with one centralized
security: block, choosing the desired SASL mechanism using a single mechanism field per listener role (client vs internal).
- Clarity: Listener ports are defined under
listeners:, while all authentication/encryption logic is contained under security:.
- Maintainability: The structure easily scales to include complex requirements (e.g., combining SASL and TLS, supporting multiple SASL types per listener, or introducing new mechanisms). This includes avoiding future complexity by separating global TLS material from per-listener TLS policies (e.g.,
clientAuth).
- Helm Chart Simplification: Generating Fluss configuration templates hopefully becomes straightforward. The chart logic determines the appropriate Fluss listeners and
security.protocol.map values by validating the single sasl.mechanism field and reading the corresponding configuration section.
Search before asking
Description
Users should be able to configure the SASL authentication options in the Helm chart values.
Willingness to contribute
Update:
02/03/2026Apache Fluss Helm SASL Support Redesign
This document proposes a redesign for configuring SASL (Simple Authentication and Security Layer) support for Apache Fluss, specifically targeting improvements in user experience and Helm chart maintainability.
Kafka Way of Configuration
The existing method for configuring security, as commonly seen in Kafka deployments, is scattered and unintuitive, requiring configuration across multiple top-level blocks.
Current Configuration Structure
Drawbacks
listeners:and related security details (like users/passwords or TLS settings) under separate, globalsasl:ortls:blocks.Our Current Approach in Development
An attempt was made to simplify configuration by embedding security details directly under the listener definitions, based on simplification of existing charts (e.g., Bitnami).
Current Configuration Structure (Example)
Drawbacks of this Approach
tls:block for certificates) would still be necessary outside the listener definitions, reintroducing fragmentation.usersblock but need unique configuration (e.g.,tokenEndpointUrl).The Helm helpers became heavy during the implementation of this approach and that the values to be input by the user are "not guided" as they could be.
For example:
If you specify SASL protocol, then you need to fill this block
The following redesign aims at being self-explanatory.
Proposed Redesign
The proposed redesign centralizes all security-related settings under a top-level
security:block, separating connection details (ports) from authentication/encryption details.Initial Proposed Configuration Structure
This initial approach makes the intent explicit (“I want client SCRAM over TLS”) and lets the chart derive listener protocols and broker config, instead of forcing users to understand all the cross-couplings.
Advantages of initial redesign
Single place to reason about security: Users choose the authentication method in one obvious block per listener role (
clientvsinternal).Chart can derive protocol:
SASL_PLAINTEXT / SASL_SSL / SSL / PLAINTEXTbecomes computed logic rather than user-filled strings.Extensible to new mechanisms (OAuth, future): add a new sub-block without changing listener definitions.
That said, there are a couple design traps worth avoiding so this stays extensible when you add TLS variants, OAuth, mTLS, multiple listeners.
Fixes to the proposed initial redesign
Mutual exclusivity and flags sprawl
With
plain.enable,scram.enable,oauth.enable, we are encoding a “one-of” choice as multiple booleans. That tends to break over time:plainandscramaccidentally?We can make it a single choice:
Then the chart:
With this the selection is a single field, and there are separate blocks for each mechanism.
TLS is both global and per listener
The TLS block could be global and per listener:
Adding tls: per listener:
This avoids the future complexity where you might need different TLS policies for internal vs client, but still reuse the same secret.
Final Proposed Values Structure
Key Benefits
security:block, choosing the desired SASL mechanism using a singlemechanismfield per listener role (client vs internal).listeners:, while all authentication/encryption logic is contained undersecurity:.clientAuth).security.protocol.mapvalues by validating the singlesasl.mechanismfield and reading the corresponding configuration section.