Cluster Security: Auth & Encryption
Imagine a bustling corporate office with a wide-open front door, unlocked file cabinets, and employees freely walking out with sensitive documents. This scenario is a security nightmare, yet it reflects the state of many default database deployments. Security in Cassandra is often overlooked until it’s too late—a data breach or unauthorized modification can compromise the entire system.
To secure a production cluster effectively, you must establish defense-in-depth across three primary fronts:
- Authentication: Verifying who the user or application is before allowing connection.
- Authorization: Verifying what the authenticated user is permitted to do, typically handled via Role-Based Access Control (RBAC).
- Encryption: Securing data while it travels across the network (mTLS) to prevent interception.
1. Authorization (RBAC)
Cassandra uses RBAC. Instead of assigning permissions to users, you assign permissions to Roles, and users assume those Roles.
Interactive RBAC Policy Simulator
Define a Role’s permissions and test access against specific resources.
1. Configure Role Permissions
2. Test Access
2. Authentication
Cassandra supports pluggable authentication. The default AllowAllAuthenticator is insecure and should never be used in production.
First Principles: Performance Impact
Enabling authentication adds a small overhead (network roundtrip for login). However, Cassandra drivers use connection pooling. Authentication happens only when a connection is established, not on every query.
- Connection Open: Auth Handshake (Slow)
- Query: Auth Token/Session ID (Fast)
Enabling Password Auth
- Update
cassandra.yaml:authenticator: PasswordAuthenticator authorizer: CassandraAuthorizer - Restart the node.
- Login with default credentials (
cassandra/cassandra). - IMMEDIATELY change the default password and create new superusers.
3. Encryption (mTLS)
Encryption is critical for preventing man-in-the-middle attacks.
- Client-to-Node: Encrypts traffic between your application and Cassandra.
- Node-to-Node (Internode): Encrypts gossip and streaming traffic. Critical because data streaming (bootstrap/repair) moves raw SSTables across the wire.
mTLS (Mutual TLS)
In standard TLS, the client verifies the server. In mTLS, both parties verify each other using certificates signed by a trusted Certificate Authority (CA).
4. Secure Drivers (Code Examples)
Connecting to a secure cluster requires configuring SSL in your driver.
import com.datastax.oss.driver.api.core.CqlSession;
import javax.net.ssl.SSLContext;
import java.net.InetSocketAddress;
import java.nio.file.Paths;
public class SecureConnect {
public static void main(String[] args) {
// Option 1: Using a Cloud Secure Connect Bundle (simplest for cloud)
// try (CqlSession session = CqlSession.builder()
// .withCloudSecureConnectBundle(Paths.get("/path/to/bundle.zip"))
// .withAuthCredentials("user", "pass")
// .build()) { ... }
// Option 2: Programmatic SSL Context (for self-managed)
try {
// Assuming you have a helper to load your KeyStore/TrustStore
SSLContext sslContext = SSLContext.getDefault();
try (CqlSession session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("10.0.0.1", 9042))
.withAuthCredentials("admin", "super_secret_password")
.withLocalDatacenter("dc1")
.withSslContext(sslContext) // Enable SSL
.build()) {
System.out.println("Connected to: " + session.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package main
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
"github.com/gocql/gocql"
)
func main() {
cluster := gocql.NewCluster("10.0.0.1", "10.0.0.2")
cluster.Keyspace = "my_keyspace"
cluster.Consistency = gocql.Quorum
// 1. Authentication
cluster.Authenticator = gocql.PasswordAuthenticator{
Username: "admin",
Password: "super_secret_password",
}
// 2. Load CA Certificate (to verify the server)
caCert, err := ioutil.ReadFile("/path/to/ca.crt")
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// 3. Load Client Certificate (for mTLS - so server verifies us)
cert, err := tls.LoadX509KeyPair("/path/to/client.crt", "/path/to/client.key")
if err != nil {
log.Fatal(err)
}
// 4. Configure TLS
cluster.SslOpts = &gocql.SslOptions{
Config: &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
// In production, InsecureSkipVerify MUST be false
InsecureSkipVerify: false,
ServerName: "cassandra.prod.local", // Must match Cert CN/SAN
},
EnableHostVerification: true,
}
session, err := cluster.CreateSession()
if err != nil {
log.Fatal(err)
}
defer session.Close()
log.Println("Secure mTLS connection established.")
}
5. Diagram: Mutual TLS (mTLS) Handshake
Figure 3: Mutual TLS requires both parties to prove their identity before data is exchanged.
6. Audit Logging
Audit logging tracks database activity, providing a forensic trail of who did what, and when. This is essential for meeting compliance frameworks (e.g., GDPR, SOC2, HIPAA) and diagnosing security incidents.
What gets logged?
By default, you can configure Cassandra to log:
- DCL (Data Control Language):
GRANT,REVOKE,CREATE ROLE. - DDL (Data Definition Language):
CREATE KEYSPACE,DROP TABLE. - DML (Data Manipulation Language):
SELECT,INSERT,UPDATE(Optional, as logging all DML can be extremely I/O intensive). - Authentication: Successful and failed login attempts.
How to Enable Audit Logging
In cassandra.yaml, look for the audit_logging_options:
audit_logging_options:
enabled: true
logger: FileAuditLogger # Recommended over BinAuditLogger for simpler parsing
included_categories: "DCL,DDL,AUTH" # Exclude DML to save disk I/O unless strictly necessary
excluded_keyspaces: "system,system_schema" # Exclude internal noise
Security Best Practice: Use external log shippers (like Filebeat or Fluentd) to immediately move audit logs off the Cassandra node to a centralized SIEM (Security Information and Event Management) system. If an attacker gains host-level access to the node, they could delete local logs to cover their tracks; shipping them externally preserves the forensic trail.