Cassanova is a web-based management interface for Apache Cassandra. Built with Python (FastAPI), it provides cluster monitoring, data exploration, and configuration-driven role-based access control.
- Stateless Authentication: Configuration-driven JWT authentication requiring no database.
- Granular Permissions: Role definitions with specific permissions (e.g.,
cluster:view,tools:cqlsh,data:write). - Access Control: Protected API endpoints and role-aware UI elements.
- Auditing: Centralized login flow with secure session handling.
- Filtering: Filter data by Partition Keys, Clustering Keys, or specific columns.
- Cross-View Integration: Filters persist across Data Layout graphs and List views.
- Data Management: Form-based row insertion, aware of table schema.
- Topology Visualization: Graphs showing Token Ring and Schema relationships.
- Schema Management: UI for creating and modifying Keyspaces and Tables.
- CQL Console: Web-based terminal with history and syntax highlighting.
- Query Tracing: List view for analyzing query performance and latency.
- Process Management: Web interfaces for
sstabledump,nodetool, andcassandra-stress.
- Cassandra Roles: View, create, modify, and delete Cassandra roles directly from the UI.
- Permission Grants: Grant and revoke per-resource permissions (SELECT, MODIFY, ALTER, etc.) with a visual access map.
- Login Filter: Toggle between all roles and login-enabled roles only.
- Access required:
roles:viewpermission.
- Side-by-side diff: Compare keyspace and table schemas across any two clusters.
- Visual tree: Hierarchical diff view with
Identical,Different,Only A, andOnly Bstatus badges. - Schema browser: Select the same cluster on both sides to browse its full schema as a tree.
- Always available: Accessible regardless of cluster count.
- Cluster Monitoring: Node status, VNode distribution, and Token Range maps.
- Multi-Cluster Support: Manage multiple Cassandra clusters from a single dashboard.
- Theming: 11 built-in themes with a quick-switch palette in the user menu.
- Navigation: Top bar with breadcrumbs, global search across clusters/keyspaces/tables, and keyboard shortcut (Ctrl+K).
To run Cassanova using Docker:
docker pull poortuna/cassanova:v1.15.0Create a cassanova.json file. This includes the auth section:
{
"app_config": {
"host": "0.0.0.0",
"port": 8080,
"routers": ["cassanova_ui_router", "cassanova_api_router"]
},
"auth": {
"enabled": true,
"secret_key": "CHANGE_THIS_SECRET_KEY",
"algorithm": "HS256",
"session_expire_minutes": 120,
"users": [
{
"username": "admin",
"password": "admin_password",
"roles": ["admin"]
},
{
"username": "viewer",
"password": "view_only_password",
"roles": ["viewer"]
}
],
"roles": [
{ "name": "admin", "permissions": ["*"] },
{ "name": "viewer", "permissions": ["cluster:view", "roles:view"] }
]
},
"clusters": {
"proda": {
"contact_points": ["10.0.0.1", "10.0.0.2"],
"port": 9042
}
},
"k8s": {
"enabled": true,
"kubeconfig": "/etc/cassanova/kubeconfig",
"contexts": null,
"namespace": "default",
"suffix": "-service",
"periodic_discovery_enabled": true,
"discovery_interval_seconds": 60,
"external_only": false,
"stale_threshold": 3
}
}Optional: Enable TLS by adding
"tls": {"enabled": true, "cert_file": "/path/to/cert.crt", "key_file": "/path/to/key.key"}underapp_config.
docker run -p 8080:8080 \
-e CASSANOVA_CONFIG_PATH=/config/cassanova.json \
-v $(pwd)/cassanova.json:/config/cassanova.json \
poortuna/cassanova:v1.15.0Note: Ensure your Cassandra nodes are reachable from within the container.
Open http://localhost:8080. Log in with the credentials defined in your JSON config.
Cassanova is configured via CASSANOVA_CONFIG_PATH.
Most UI settings support hot-reloading. Auth changes require a restart.
Cassanova can discover K8ssandraCluster instances from a Kubernetes cluster.
| Setting | Description | Default |
|---|---|---|
k8s.enabled |
Enable K8s discovery on startup | false |
k8s.kubeconfig |
Path to kubeconfig file | null |
k8s.namespace |
Namespace to scan (or all if null) | null |
k8s.suffix |
Service name suffix (e.g., -metallb) |
-service |
k8s.periodic_discovery_enabled |
Enable periodic background scans | false |
k8s.discovery_interval_seconds |
Interval for periodic scans in seconds | 60 |
k8s.external_only |
Only accept LoadBalancer IPs and externalIPs; skip ClusterIP and DNS |
false |
k8s.stale_threshold |
Consecutive missed scans before a discovered cluster is evicted | 3 |
Mechanism:
- Cassanova scans for
K8ssandraClusterCRs. - Fetches credentials from the
<cluster>-superuserSecret. - Identifies Services matching
<cluster>-<dc><suffix>to extract contact points. - Merges discovered clusters into the configuration.
- Clusters not seen for
stale_thresholdconsecutive scans are evicted and their sessions closed.
external_onlymode: When enabled, only LoadBalancer ingress IPs andexternalIPsare accepted as contact points. Useful when Cassanova runs outside the cluster (e.g., external monitoring host) and must reach Cassandra via MetalLB or cloud load balancers rather than internal DNS.
Cassanova exposes a cluster inventory endpoint for operators and automation.
Requires permission: cluster:admin
| Endpoint | Method | Description |
|---|---|---|
/api/v1/admin/clusters |
GET |
List all registered clusters with provenance metadata |
Query parameters:
| Parameter | Default | Description |
|---|---|---|
expose_credentials |
true |
Include plaintext credentials in the response. Set to false to mask them. |
Example response:
[
{
"name": "my-cluster",
"source": "k8s",
"context": null,
"contact_points": ["10.0.0.249"],
"port": 9042,
"credentials": { "username": "my-cluster-superuser", "password": "..." },
"jmx_credentials": null,
"has_credentials": true,
"has_jmx_credentials": false,
"has_additional_kwargs": false,
"last_seen": "2026-05-09T20:19:24Z",
"miss_count": 0
}
]Includes a dashboard to handle Cassandra node failures in Kubernetes (e.g., OpenShift with LVMS).
| Setting | Description | Default |
|---|---|---|
k8s.node_recovery.enabled |
Enable the node recovery service | false |
Recovery Workflow:
- Detect: Queries for
Pendingpods with Volume Node Affinity issues. - Review: Administrator approves the recovery.
- Recover: Creates a
K8ssandraTask(replacenode) to fix the pod.
Supports TLS encryption.
| Setting | Description | Default |
|---|---|---|
app_config.tls.enabled |
Enable HTTPS/TLS | false |
app_config.tls.cert_file |
Path to SSL certificate (.crt/.pem) | Required if enabled |
app_config.tls.key_file |
Path to private key (.key/.pem) | Required if enabled |
app_config.tls.ca_bundle |
Optional CA certificate chain | null |
app_config.tls.min_tls_version |
Minimum TLS version (TLSv1_2 or TLSv1_3) |
TLSv1_2 |
app_config.tls.enforce_https |
Redirect HTTP → HTTPS (301) | true |
app_config.tls.hsts_enabled |
Enable HSTS security headers | true |
app_config.tls.hsts_max_age |
HSTS max-age in seconds | 31536000 (1 year) |
app_config.tls.hsts_include_subdomains |
Apply HSTS to subdomains | false |
Security Features:
- Cipher Suites - ECDHE/CHACHA20/AES-GCM ciphers
- Protocols - TLS 1.2+ enforcement
- HSTS - Prevents downgrade attacks
- Secure Cookies - Session cookies marked
SecureandSameSite=Lax - Redirects - Forces HTTPS connections
Supports LDAP/AD integration for centralized user management.
| Setting | Description | Default |
|---|---|---|
auth.ldap.enabled |
Enable LDAP auth | false |
auth.ldap.server_uri |
LDAP URI (ldap:// or ldaps://) | ldap://localhost:389 |
auth.ldap.base_dn |
Base DN for user/group search | dc=example,dc=com |
auth.ldap.bind_dn |
Service account DN (null for anonymous) | null |
auth.ldap.role_mapping |
Map LDAP groups to Cassanova roles | {} |
Role Mapping Strategies:
- Group Name: Matches the
cn(or configured attribute) of the group. e.g.,"Domain Admins": ["admin"]. - Exact DN: Matches the full Distinguished Name of the group. e.g.,
"cn=group,dc=com": ["admin"]. - Branch/Suffix: Matches any group located under a specific OU. e.g.,
"ou=Admins,dc=com": ["admin"].
Example Config:
"auth": {
"enabled": true,
"ldap": {
"enabled": true,
"server_uri": "ldaps://ad.example.com:636",
"bind_dn": "cn=svc-cassanova,ou=Users,dc=example,dc=com",
"bind_password": "secret_password",
"base_dn": "dc=example,dc=com",
"user_search_filter": "(sAMAccountName={username})",
"group_search_base": "ou=Groups,dc=example,dc=com",
"group_search_filter": "(member={user_dn})",
"role_mapping": {
"Domain Admins": ["admin"],
"Developers": ["viewer"],
"cn=SpecificGroup,ou=Groups,dc=example,dc=com": ["admin"],
"ou=NuclearBranch,dc=example,dc=com": ["admin"]
}
}
}To run locally (Linux/WSL recommended):
git clone https://github.com/poortuna/cassanova
cd cassanova
pip install uv
uv pip install -e ".[dev]"
# Set config path
export CASSANOVA_CONFIG_PATH=./cassanova.json
# Run Server
python -m cassanova.runruff check . # Lint
ruff format . # Format
mypy cassanova/ # Type check
pytest tests/ -vv # Run tests
pre-commit install # Set up git hooksCassanova is open source, licensed under the MIT License.



