Secure Apache Cassandra with cnspec
Scan Apache Cassandra clusters, roles, and keyspaces against security and compliance best practices with cnspec.
Scan your Apache Cassandra clusters to find security risks before they become incidents. cnspec evaluates the cluster's authentication, authorization, client and internode encryption, and audit logging, along with its roles and permission grants, nodes, and keyspace replication.
cnspec connects over CQL and inventories the cluster through read-only queries against the system and system_auth keyspaces and the system_views.settings virtual table. It never touches your data.
If you're new to cnspec, start with the Quickstart. For an overview of every database cnspec can scan, see the database scanning overview.
Prerequisites
To scan Cassandra with cnspec, you must have:
- cnspec installed on your workstation
- Network access to the cluster on its CQL port (9042 by default)
- A role with
SELECTon thesystem,system_schema,system_auth, andsystem_viewskeyspaces
Authenticate
cnspec authenticates with a Cassandra role and password through the PasswordAuthenticator:
cnspec shell cassandra db.contoso.com --user cassandra --ask-passFor a TLS connection, add the TLS flags:
cnspec shell cassandra db.contoso.com --user auditor --ask-pass --tls --tls-ca ca.pemPrefer a least-privileged role for auditing. Without the system_auth and system_views grants the cluster still resolves, while the security posture and roles come back null or empty rather than failing the scan.
When the cluster runs the default AllowAllAuthenticator, no credentials are needed at all and the roles table is empty. cassandra.cluster.security.authenticationEnabled reports that, and it's the first thing worth checking.
Connection options
| Option | Description |
|---|---|
--host | Cluster hostname or IP address (also accepted as the positional argument) |
--port | CQL native transport port (default 9042) |
--user, -u | Role to authenticate as |
--password, -p | Password, or --ask-pass to be prompted |
--tls | Connect over TLS |
--tls-ca | Path to a CA certificate to verify the cluster |
--tls-insecure | Skip TLS certificate verification (testing only) |
Verify with a quick Cassandra check
cnspec shell cassandra db.contoso.com --user cassandra --ask-passcnspec> cassandra.cluster { name version }
cassandra.cluster: {
name: "Test Cluster"
version: "5.0.8"
}If cnspec connects and shows the version, you're ready to scan.
Scan Cassandra
cnspec scan cassandra db.contoso.com --user auditor --ask-passWhen a scan completes, cnspec prints a summary of all the checks it ran, grouped by policy, along with a risk score from 0 (no risk) to 100 (highest risk). Failed checks include remediation guidance to help you fix issues. To learn more about reading scan results, read Understand cnspec Results.
Mondoo doesn't yet ship an out-of-the-box Cassandra policy. The resources are shaped around the CIS Apache Cassandra Benchmark, so the checks below map closely to its recommendations. Use them as a starting point and create your own policies to meet your requirements.
Explore and test checks interactively
cnspec shell cassandra db.contoso.com --user auditor --ask-passRead the cluster's security posture
cnspec> cassandra.cluster.security { authenticationEnabled authorizationEnabled clientEncryptionEnabled internodeEncryption auditLoggingEnabled }
cassandra.cluster.security: {
authenticationEnabled: true
authorizationEnabled: true
clientEncryptionEnabled: false
internodeEncryption: "none"
auditLoggingEnabled: false
}List roles
cnspec> cassandra.cluster.roles { name canLogin isSuperuser hasPassword memberOf }Inspect a role's permission grants
cnspec> cassandra.cluster.roles.where(name == "auditor").first.permissions { resource permissions }List keyspaces and their replication
cnspec> cassandra.cluster.keyspaces.where(isSystem == false) { name replicationStrategy replicationFactors durableWrites }List nodes
cnspec> cassandra.cluster.nodes { address datacenter rack releaseVersion }Example security checks
Ensure authentication is enabled
The default AllowAllAuthenticator accepts any client that can reach the port:
cnspec> cassandra.cluster.security.authenticationEnabled == true
[ok] value: trueEnsure authorization is enforced
Authentication without authorization identifies the caller but grants everyone the same access:
cnspec> cassandra.cluster.security.authorizationEnabled == true
[ok] value: trueEnsure client traffic is encrypted
cnspec> cassandra.cluster.security.clientEncryptionEnabled == true
[ok] value: trueEnsure internode traffic is encrypted
dc and rack encrypt only across those boundaries, leaving traffic inside one unencrypted:
cnspec> cassandra.cluster.security.internodeEncryption == "all"
[ok] value: trueEnsure audit logging is enabled
cnspec> cassandra.cluster.security.auditLoggingEnabled == true
[ok] value: trueEnsure the default cassandra superuser is not still in use
The default account is the first credential anyone tries:
cnspec> cassandra.cluster.roles.where(name == "cassandra").none(canLogin == true)
[ok] value: trueEnsure superuser is not granted broadly
cnspec> cassandra.cluster.roles.where(isSuperuser && canLogin) { name }Ensure every login role has a password
cnspec> cassandra.cluster.roles.where(canLogin).all(hasPassword == true)
[ok] value: trueEnsure no role holds AUTHORIZE on all data
A role with AUTHORIZE can grant its own access to anyone else, which makes every other permission grant provisional:
cnspec> cassandra.cluster.roles.all(permissions.where(resource == "data").none(permissions.contains("AUTHORIZE")))
[ok] value: trueEnsure application keyspaces use NetworkTopologyStrategy
SimpleStrategy ignores data center topology, so replicas can all land in one failure domain:
cnspec> cassandra.cluster.keyspaces.where(isSystem == false).all(replicationStrategy == "NetworkTopologyStrategy")
[ok] value: trueEnsure application keyspaces keep durable writes on
Turning durable writes off skips the commit log, so an unclean shutdown loses acknowledged writes:
cnspec> cassandra.cluster.keyspaces.where(isSystem == false).all(durableWrites == true)
[ok] value: trueReview roles granted to other roles
cnspec> cassandra.cluster.roles.where(memberOf.length > 0) { name memberOf }Learn more
- Apache Cassandra Resource Pack Reference: every Cassandra resource and field cnspec can query
- Write Effective MQL: guide to authoring checks and queries
CIS recommendations that cover cassandra.yaml permissions, keystore permissions, and JMX configuration aren't reachable over CQL. Scan the cluster's hosts with the os provider to cover them.