Apache Cassandra / ScyllaDB Integration Guide

This guide covers how to connect a Cassandra or ScyllaDB cluster to BurnLedger, configure query templates, and set up read-only credentials. The connector is implemented and registered as connector type cassandra.


Connection Configuration

BurnLedger connects to Cassandra using the CQL native protocol.

Configuration fields:

Field Required Description
hosts Yes Array of contact point addresses (e.g., ["cass1.example.com", "cass2.example.com"]).
port No CQL port (default: 9042).
keyspace Yes The keyspace containing the target table.
username No CQL username for authentication.
password No CQL password.
datacenter No Local datacenter for DCAwareRoundRobinPolicy.
tls No Enable TLS (default: true). Minimum TLS 1.2.
read_only Conditional Your assertion that the credential is read-only. Required when permissions cannot be listed — no username supplied, or the cluster uses AllowAllAuthorizer. Ignored when LIST ALL PERMISSIONS succeeds. See Read-Only User Setup.

These are the exact JSON keys the connector reads. read_only is snake_case in both SDKs — do not write readOnly.

TypeScript

const system = await bl.registerSystem({
  name: "user-events-cass",
  connectorType: "cassandra",
  connectionConfig: {
    hosts: ["cass1.example.com", "cass2.example.com"],
    keyspace: "myapp",
    username: "burnledger_ro",
    password: process.env.CASS_PASSWORD,
    datacenter: "us-east-1",
  },
  subjectQuery: "SELECT * FROM user_events WHERE user_id = ?",
});

Python

system = bl.register_system(
    name="user-events-cass",
    connector_type="cassandra",
    connection_config={
        "hosts": ["cass1.example.com", "cass2.example.com"],
        "keyspace": "myapp",
        "username": "burnledger_ro",
        "password": os.environ["CASS_PASSWORD"],
        "datacenter": "us-east-1",
    },
    subject_query="SELECT * FROM user_events WHERE user_id = ?",
)

Query Template Format

CQL query templates use ? as the parameter placeholder (standard CQL prepared statement syntax).

Rules:

  • Must contain exactly one ? placeholder — the subject identifier is bound to it as the single query parameter. A template with a different count of ? is rejected by the CQL driver at query time (surfaced as CONNECTION_FAILED).
  • Should begin with SELECT, and the ? should sit in the WHERE clause on the partition key (Cassandra needs the partition key for an efficient, non-scanning read).
  • Do not use ALLOW FILTERING — a full table scan will blow past max_records and cost you cluster time.

Not validated at registration. Unlike the SQL and JSON connectors, Cassandra templates are not checked when the system is registered: BurnLedger does not verify that the template starts with SELECT, targets the partition key, or omits ALLOW FILTERING. Cassandra itself enforces the partition-key and ALLOW FILTERING rules at execution time, and a bad template surfaces as a query error rather than a registration error. Review your template carefully.

Examples:

-- Query by partition key
SELECT * FROM user_events WHERE user_id = ?

-- Specific columns
SELECT user_id, event_type, event_data, created_at FROM user_events WHERE user_id = ?

-- Compound partition key (first element)
SELECT * FROM user_data WHERE tenant_id = 'default' AND user_id = ?

Read-Only User Setup

BurnLedger detects write access during connection validation and rejects roles that have it — without ever writing. It runs LIST ALL PERMISSIONS OF <role> and allows only SELECT and DESCRIBE. Any other permission — MODIFY, CREATE, ALTER, DROP, AUTHORIZE, EXECUTE, or anything unrecognized — is treated as write-capable (default-deny) and construction is refused.

This works automatically when the cluster uses a permission-enforcing authorizer (e.g. CassandraAuthorizer). If no username is configured, or the cluster uses AllowAllAuthorizer (no permission system, so permissions cannot be listed), set "read_only": true in the connector config to assert read-only; otherwise construction is refused (fails closed).

Cassandra (native auth)

-- Create a role with login and no superuser
CREATE ROLE burnledger_ro WITH PASSWORD = 'your-secure-password' AND LOGIN = true AND SUPERUSER = false;

-- Grant SELECT on specific tables
GRANT SELECT ON myapp.user_events TO burnledger_ro;
GRANT SELECT ON myapp.user_profiles TO burnledger_ro;

-- Or grant SELECT on all tables in the keyspace
GRANT SELECT ON ALL TABLES IN KEYSPACE myapp TO burnledger_ro;

ScyllaDB

Same CQL syntax as Cassandra. ScyllaDB uses the same auth model.

Amazon Keyspaces (Managed Cassandra)

Use service-specific credentials from the IAM console. Attach a policy with cassandra:Select only:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["cassandra:Select"],
      "Resource": "arn:aws:cassandra:us-east-1:123456789012:/keyspace/myapp/table/user_events"
    }
  ]
}

Verify

-- Connect as read-only role
cqlsh cass1.example.com -u burnledger_ro -p 'your-secure-password'

-- Should succeed
SELECT * FROM myapp.user_events WHERE user_id = 'test-user' LIMIT 1;

-- Should fail with "Unauthorized"
INSERT INTO myapp.user_events (user_id, event_type) VALUES ('test', 'test');
DELETE FROM myapp.user_events WHERE user_id = 'test-user';

Hash Scope

hash_scope is accepted on the system record for every connector, but the Cassandra connector does not read it — it only changes behavior for the object/document-store connectors (S3, GCS, Azure Blob, MarkLogic). Setting hashScope: "existence" on a Cassandra system does not switch to a primary-key-only hash; it has no effect at all.

What actually varies is the proof mode of the attestation:

Proof mode Cassandra behavior
Count (default) Executes the template and counts matching rows. No row content is hashed.
Merkle (opt-in) Executes the template and hashes every column of each row, columns sorted by name for deterministic hashing.

Cassandra-Specific Considerations

Partition key requirement

Cassandra queries should include the full partition key in the WHERE clause. This is enforced by Cassandra, not by BurnLedger: a template that omits it fails at query time (or demands ALLOW FILTERING) and surfaces as CONNECTION_FAILED. BurnLedger performs no partition-key analysis of the template.

TTL and tombstones

If your data uses TTLs, records may disappear between attestation and verification without explicit deletion. This is expected behavior — BurnLedger proves absence regardless of how the data was removed.

Consistency level

BurnLedger uses LOCAL_QUORUM consistency for reads to balance accuracy and availability. This means a majority of the replicas in the local datacenter must respond — not all of them. Set datacenter in the config so the driver routes to the intended local DC.

That level is now disclosed rather than left in the source: POST /v1/systems/test-connection reports replication.role: no_primary — every Cassandra node is a peer, so there is no primary to be behind — with the configured level in replication.detail. A write acknowledged at a quorum of the same datacenter cannot be missed by a LOCAL_QUORUM read; a keyspace replicated across datacenters can still answer from a local quorum that has not received a remote write. See endpoint role.


Troubleshooting

Error Cause Fix
CONNECTION_FAILED Cannot reach any contact point Verify hosts and port, check firewall rules.
CONNECTION_FAILED with "Unauthorized" Invalid credentials Check username and password.
WRITE_ACCESS_DETECTED Role holds a permission outside SELECT/DESCRIBE (e.g. MODIFY) Revoke it: REVOKE MODIFY ON myapp.user_events FROM burnledger_ro;
CONNECTION_FAILED with "cannot verify the credential is read-only" No username configured, or the cluster uses AllowAllAuthorizer, so LIST ALL PERMISSIONS cannot run Enable CassandraAuthorizer and connect as a named role, or set "read_only": true in the connector config.
CONNECTION_FAILED with "ALLOW FILTERING" Cassandra rejected the query as a full table scan Rewrite the template to target the partition key. BurnLedger does not catch this at registration.
© 2026 ProChatFlow LLC Last updated present → absent → proven