Password validation and generation
Here’s the problem: while users have always had the ability to create whatever password they wanted in Cassandra - from straightforward to incredibly complex and everything in between–this ultimately created a noticeable security vulnerability.
While organizations might have internal processes for generating secure passwords that adhere to their own security policies,
Cassandra itself did not have the means to enforce these standards. To make the security vulnerability worse,
if a password initially met internal security guidelines, users could later downgrade their password to
a less secure option simply by using ALTER ROLE statements.
When internal password requirements are enforced for an individual, users face the additional burden of creating compliant passwords. This inevitably involved lots of trial-and-error in attempting to create a compliant password that satisfied complex security roles.
But what if there was a way to have Cassandra automatically create passwords that meet all bespoke security requirements–but without requiring manual effort from users or system operators?
That’s why we developed CEP-24: Password validation/generation. We recognized that the complexity of secure password management could be significantly reduced (or eliminated entirely) with the right approach –and improving both security and user experience at the same time.
The Goals of CEP-24
A Cassandra Enhancement Proposal (or CEP) is a structured process for proposing, creating, and ultimately implementing new features for the Cassandra project. All CEPs are thoroughly vetted among the Cassandra community before they are officially integrated into the project.
These were the key goals we established for CEP-24:
-
Introduce a way to enforce password strength upon role creation or role alteration.
-
Implement a reference implementation of a password validator which adheres to a recommended password strength policy, to be used for Cassandra users out of the box.
-
Emit a warning (and proceed) or just reject
CREATE ROLEandALTER ROLEstatements when the provided password does not meet a certain security level, based on user configuration of Cassandra. -
To be able to implement a custom password validator with its own policy, whatever it might be, and provide a modular/pluggable mechanism to do so.
-
Provide a way for Cassandra to generate a password which would pass the subsequent validation for use by the user.
The Cassandra Password Validator and Generator builds upon an established framework in Cassandra called Guardrails, which was originally implemented under CEP-3 (more details here).
Implementation and configuration
The password validator implements a custom guardrail introduced as part of CEP-24. A custom guardrail can validate and
generate values of arbitrary types when properly implemented. In the CEP-24 context,
the password guardrail provides CassandraPasswordValidator by extending ValueValidator,
while passwords are generated by CassandraPasswordGenerator by extending ValueGenerator.
Both components work with passwords as String type values.
Password validation and generation are configured in cassandra.yaml file under the password_policy section.
Let’s explore the key configuration properties available.
First, the class_name and generator_class_name parameters
specify which validator and generator classes will be used to validate and generate passwords respectively.
Cassandra ships CassandraPasswordValidator and CassandraPasswordGenerator out of the box.
However, if a particular enterprise decides that they need something very custom, they are free to implement their own validators,
put it on Cassandra’s class path and reference it in the configuration behind class_name parameter. Same for the validator.
CEP-24 provides implementations of the validator and generator that the Cassandra team believes will satisfy the requirements of most users. These default implementations address common password security needs. However, the framework is designed with flexibility in mind, allowing organizations to implement custom validation and generation rules that align with their specific security policies and business requirements.
password_policy: # Implementation class of a validator. When not in form of FQCN, the # package name org.apache.cassandra.db.guardrails.validators is prepended. # By default, there is no validator. validator_class_name: CassandraPasswordValidator # Implementation class of related generator which generates values # which are valid when tested against this validator. # When not in form of FQCN, the package name # org.apache.cassandra.db.guardrails.generators is prepended. # By default, there is no generator. generator_class_name: CassandraPasswordGenerator
Password quality might be looked at as the number of characteristics a password satisfies. There are two levels for any password to be evaluated – warning level and failure level. Warning and failure levels nicely fit into how Guardrails act. Every guardrail has warning and failure thresholds. Based on what value a specific guardrail evaluates, it will either emit a warning to a user that its usage is discouraged (but ultimately allowed), or it will fail to be set altogether.
This same principle applies to password evaluation – each password is assessed against both warning and failure thresholds. These thresholds are determined by counting the characteristics present in the password.
The system evaluates five key characteristics:
-
the password’s overall length
-
the number of uppercase characters
-
the number of lowercase characters
-
the number of special characters
-
and the number of digits.
A comprehensive password security policy can be enforced by configuring minimum requirements for each of these characteristics.
# There are four characteristics (excluding password's length): # upper-case, lower-case, special character and digit. # If this value is set e.g. to 3, a password has to # consist of 3 out of 4 characteristics. # For example, it has to contain at least 2 upper-case characters, # 2 lower-case, and 2 digits to pass, # but it does not have to contain any special characters. # If the number of characteristics found in the password is # less than or equal to this number, it will emit a warning. characteristic_warn: 3 # If the number of characteristics found in the password is #less than or equal to this number, it will emit a failure. characteristic_fail: 2
Next, there are configuration parameters for each characteristic which count towards warning or failure:
# If the password is shorter than this value, # the validator will emit a warning. length_warn: 12 # If a password is shorter than this value, # the validator will emit a failure. length_fail: 8 # If a password does not contain at least n # upper-case characters, the validator will emit a warning. upper_case_warn: 2 # If a password does not contain at least # n upper-case characters, the validator will emit a failure. upper_case_fail: 1 # If a password does not contain at least # n lower-case characters, the validator will emit a warning. lower_case_warn: 2 # If a password does not contain at least # n lower-case characters, the validator will emit a failure. lower_case_fail: 1 # If a password does not contain at least # n digits, the validator will emit a warning. digit_warn: 2 # If a password does not contain at least # n digits, the validator will emit a failure. digit_fail: 1 # If a password does not contain at least # n special characters, the validator will emit a warning. special_warn: 2 # If a password does not contain at least # n special characters, the validator will emit a failure. special_fail: 1
There is also a maximum password length parameter. Passwords exceeding this length will be rejected:
# Maximum allowed password length. Defaults to 1000. max_length: 1000
It is also possible to say that illegal sequences of certain length found in a password will be forbidden:
# If a password contains illegal sequences that are at least this long, it is invalid. # Illegal sequences might be either alphabetical (form 'abcde'), # numerical (form '34567'), or US qwerty (form 'asdfg') as well # as sequences from supported character sets. # The minimum value for this property is 3, # by default it is set to 5. illegal_sequence_length: 5
The built-in CassandraPasswordValidator uses the Passay library for illegal sequence detection, which supports the following character sets: English, Cyrillic (classic and modern), German, Polish, and Czech.
Lastly, it is also possible to configure a dictionary of passwords to check against. That way, we will be checking against password dictionary attacks. It is up to the operator of a cluster to configure the password dictionary:
# Dictionary to check the passwords against. Defaults to no dictionary. # Whole dictionary is cached into memory. Use with caution with relatively big dictionaries. # Entries in a dictionary, one per line, have to be sorted per String's compareTo contract. dictionary: /path/to/dictionary/file
Now that we have gone over all the configuration parameters, let’s take a look at an example of how password validation and generation look in practice.
Validation and generation of a password
Consider a scenario where a Cassandra super-user (such as the default ‘cassandra’ role) attempts to create a new role named ‘alice’.
cassandra@cqlsh> CREATE ROLE alice WITH PASSWORD = 'cassandraisadatabase' AND LOGIN = true; InvalidRequest: Error from server: code=2200 [Invalid query] message="Password was not set as it violated configured password strength policy. To fix this error, the following has to be resolved: Password contains the dictionary word 'cassandraisadatabase'. You may also use 'GENERATED PASSWORD' upon role creation or alteration."
The password is in the dictionary. When an operator sees this, they will try to fix it by creating some random password not in dictionary:
cassandra@cqlsh> CREATE ROLE alice WITH PASSWORD = 'T8aum3?' AND LOGIN = true; InvalidRequest: Error from server: code=2200 [Invalid query] message="Password was not set as it violated configured password strength policy. To fix this error, the following has to be resolved: Password must be 8 or more characters in length. You may also use 'GENERATED PASSWORD' upon role creation or alteration."
Password is not in the dictionary, but it is not long enough. In the following example, the password is finally set, but it is not considered to be secure enough. It satisfies the minimum requirements but our validator identified that not all characteristics were met.
cassandra@cqlsh> CREATE ROLE alice WITH PASSWORD = 'mYAtt3mp' AND LOGIN = true; Warnings: Guardrail password violated: Password was set, however it might not be strong enough according to the configured password strength policy. To fix this warning, the following has to be resolved: Password must be 12 or more characters in length. Passwords must contain 2 or more digit characters. Password must contain 2 or more special characters. Password matches 2 of 4 character rules, but 4 are required. You may also use 'GENERATED PASSWORD' upon role creation or alteration.
When an operator saw this, they noticed the note about the GENERATED PASSWORD clause which will
generate a password automatically without an operator needing to invent it on their own.
This is a lot of times, as shown, a cumbersome process better to be left on a machine.
cassandra@cqlsh> ALTER ROLE alice WITH GENERATED PASSWORD; generated_password ------------------ R7tb33?.mcAX
The generated password shown above will satisfy all the rules we have configured in cassandra.yaml automatically.
Every generated password will satisfy all the rules. This is clearly an advantage over manual password generation.
When the CQL statement is executed, it will be visible in the CQLSH history (HISTORY command or in cqlsh_history file)
but the password will not be logged, hence it cannot leak. It will also not appear in any auditing logs.
Previously, Cassandra had to obfuscate such statements. This is not necessary anymore.
We can create a role with generated password like this:
cassandra@cqlsh> CREATE ROLE alice WITH GENERATED PASSWORD AND LOGIN = true;
When a password is generated for alice she can log in:
$ cqlsh -u alice -p R7tb33?.mcAX ... alice@cqlsh>
| It is recommended to save password to ~/.cassandra/credentials, for example: |
[PlainTextAuthProvider] username = cassandra password = R7tb33?.mcAX
and by setting auth_provider in ~/.cassandra/cqlshrc
[auth_provider] module = cassandra.auth classname = PlainTextAuthProvider
It is also possible to configure password validators in such a way that a user does not see why a password failed.
This is driven by configuration property for password_policy called detailed_messages. When set to false,
the violations will be very brief:
alice@cqlsh> ALTER ROLE alice WITH PASSWORD = 'myattempt'; InvalidRequest: Error from server: code=2200 [Invalid query] message="Password was not set as it violated configured password strength policy. You may also use 'GENERATED PASSWORD' upon role creation or alteration."
Several potential enhancements to password generation and validation could be implemented in future releases. One promising extension would be validating new passwords against previous values. This would prevent users from reusing passwords until after they’ve created a specified number of different passwords. A related enhancement could include restricting how frequently users can change their passwords, preventing rapid cycling through passwords to circumvent history-based restrictions.
These features, while valuable for comprehensive password security, were considered beyond the scope of the initial implementation and may be addressed in future updates.
Runtime configuration
Since this solution is based on guardrails which are configurable via JMX in runtime, same hold for
password validator, also configured via GuardrailsMBean as any other guardrails. There are two methods exposed:
-
Map<String, Object> getPasswordPolicy()- gets password validator configuration as JSON string, -
void setPasswordPolicy(String value)- reconfigures the password validator by reading and parsing the configuration from the provided String, being JSON representation of configuration map. Reconfiguration of password validator in runtime is considered to be very sensitive operation. If an operator evaluates the reconfiguration in runtime is not allowed, they might setpassword_policy_reconfiguration_enabledtofalseincassandra.yamlto disable it.
Diagnostic events
If diagnostic event’s framework is enabled and consumers are subscribed to them, diagnostic events about warning and failures to generate a password will be published.
Final thoughts and next steps
The Cassandra Password Validator and Generator implemented under CEP-24 represents a significant improvement in Cassandra’s security posture.
By providing robust, configurable password policies with built-in enforcement mechanisms and convenient password generation capabilities, organizations can now ensure compliance with their security standards directly at the database level. This not only strengthens overall system security but also improves the user experience by eliminating guesswork around password requirements.
As Cassandra continues to evolve as an enterprise-ready database solution, these security enhancements demonstrate a commitment to meeting the demanding security requirements of modern applications while maintaining the flexibility that makes Cassandra so powerful.