This check flags GCP firewall rules that expose Cassandra's inter-node port (7001) to the public internet (0.0.0.0/0). An open Cassandra cluster is an open door to data theft and node takeover. Restrict the source ranges to internal subnets or specific bastion IPs and confirm no node-to-node traffic ever crosses the public edge.
Cassandra is a workhorse for high-throughput, distributed workloads, which means it often holds a lot of data you really do not want strangers reading. When a VPC firewall rule on Google Cloud allows traffic on port 7001 from 0.0.0.0/0, you have effectively published an internal database protocol to the entire internet. This check, vpc_opencassandra, exists to catch exactly that mistake before someone else does.
Below we cover what the check looks for, why an exposed Cassandra port is a genuine business risk, how to close the hole, and how to keep it closed.
What this check detects
The check scans your GCP VPC firewall rules for any INGRESS rule that:
- Is in an
ALLOWstate (not denied) - Permits TCP traffic on port 7001
- Has a source range that includes the public internet, typically
0.0.0.0/0or an overly broad CIDR block
Port 7001 is Cassandra's TLS-encrypted inter-node communication port, used for the gossip protocol and data replication between nodes in a cluster. Its plaintext counterpart is 7000. Neither should ever be reachable from outside your private network. Client traffic uses port 9042 (CQL), which is also internal-only in any sane deployment.
Note: Port 7001 carries node-to-node gossip and replication, not application queries. There is no legitimate reason for it to accept connections from arbitrary public addresses. If it does, the rule was almost certainly created by accident or copied from a permissive template.
Why it matters
An open Cassandra port is not a theoretical concern. Internet-wide scanners like Shodan and Censys index exposed database ports continuously, and automated bots probe newly opened addresses within minutes. Here is what an attacker can do once they reach your cluster.
Data exfiltration
Cassandra historically shipped with authentication disabled by default. Many clusters still run with AllowAllAuthenticator because someone meant to lock it down later and never did. If your nodes are reachable and auth is off, an attacker connects, runs DESCRIBE KEYSPACES, and starts pulling tables. No exploit required.
Cluster takeover and poisoning
The gossip protocol on 7001 is how nodes discover and trust each other. An attacker who can speak gossip to your cluster can attempt to join a rogue node, learn the full topology, and in some configurations interfere with replication. That turns a read-only data leak into a write-capable foothold.
Ransom and destruction
Exposed databases are a favorite target for ransom campaigns. The pattern is well documented across MongoDB, Elasticsearch, and Cassandra: attackers dump the data, drop the keyspaces, and leave a table behind demanding cryptocurrency to get it back. If you have no recent backup, that is potentially an unrecoverable loss.
Danger: If this firewall rule has been live for any length of time, treat the cluster as potentially compromised. Check Cassandra system logs and VPC flow logs for connections from unfamiliar IPs before you simply close the port and move on. Closing the door does not undo a break-in that already happened.
How to fix it
The fix is to restrict the offending rule's source ranges to the internal addresses that actually need cluster access. You have a few options depending on your tooling.
Step 1: Find the offending rule
List firewall rules that allow port 7001 and inspect their source ranges:
gcloud compute firewall-rules list \
--filter="allowed.ports=7001 AND direction=INGRESS" \
--format="table(name, sourceRanges.list(), allowed[].map().firewall_rule().list(), network)"
Look for any rule whose source range shows 0.0.0.0/0. That is your culprit.
Step 2: Decide on a correct source range
Cassandra node-to-node traffic should be scoped to the subnet or subnets where your nodes live. If you administer the cluster from a bastion host, add only that host's address. For example, an internal RFC 1918 range such as 10.0.0.0/16 or a tighter /24 matching your data subnet.
Step 3: Update the rule
Warning: Changing the source range on a live rule can break replication if you scope it too tightly and leave out a node's subnet. Confirm every node IP falls inside the new range before applying. A brief check with nodetool status after the change will tell you if any node dropped out of the ring.
gcloud compute firewall-rules update allow-cassandra-7001 \
--source-ranges=10.0.0.0/24
If you would rather replace the rule entirely with a clean one, delete the bad rule and create a scoped replacement:
# Delete the over-permissive rule
gcloud compute firewall-rules delete allow-cassandra-7001
# Create a scoped internal-only rule
gcloud compute firewall-rules create allow-cassandra-internal \
--network=cassandra-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:7000,tcp:7001,tcp:9042 \
--source-ranges=10.0.0.0/24 \
--target-tags=cassandra-node
Step 4: Verify
From an external host, confirm the port no longer answers:
nc -vz YOUR_NODE_PUBLIC_IP 7001
# Expect: connection refused or timeout
Then confirm the cluster is still healthy from inside the VPC:
nodetool status
# All nodes should show UN (Up/Normal)
Tip: Better still, give your Cassandra nodes no public IP at all. If the nodes only have internal addresses and you reach them through Cloud NAT and IAP, an accidental open firewall rule has nothing to expose to the internet in the first place.
Fixing it with Terraform
If your infrastructure is managed as code, the firewall rule should be corrected in the source, not in the console, or your next terraform apply will reopen the hole. Here is a scoped rule definition:
resource "google_compute_firewall" "cassandra_internal" {
name = "allow-cassandra-internal"
network = google_compute_network.cassandra_vpc.name
direction = "INGRESS"
allow {
protocol = "tcp"
ports = ["7000", "7001", "9042"]
}
# Scope to the data subnet only, never 0.0.0.0/0
source_ranges = ["10.0.0.0/24"]
target_tags = ["cassandra-node"]
}
Search your codebase for any source_ranges containing 0.0.0.0/0 alongside these ports and remove them. A quick grep saves a lot of guesswork:
grep -rn "0.0.0.0/0" --include="*.tf" .
How to prevent it from happening again
One-off fixes do not stick. The goal is to make it impossible to merge a public Cassandra rule in the first place.
Block it in CI with policy-as-code
If you use Terraform, an OPA or Conftest policy can fail the build when a firewall rule combines a public source with sensitive database ports. A Rego rule looks like this:
package firewall
deny[msg] {
rule := input.resource.google_compute_firewall[name]
rule.source_ranges[_] == "0.0.0.0/0"
port := rule.allow[_].ports[_]
sensitive := {"7000", "7001", "9042"}
sensitive[port]
msg := sprintf("Firewall '%s' exposes Cassandra port %s to the public internet", [name, port])
}
Wire that into your pipeline so the plan fails before anything reaches GCP:
terraform plan -out=tfplan
terraform show -json tfplan | conftest test -
Use a hierarchical firewall policy
At the organization or folder level, GCP lets you define hierarchical firewall policies that individual projects cannot override. A deny rule on common database ports from public ranges acts as a backstop even when a project owner makes a mistake.
Continuous monitoring
Policy gates catch new changes, but they do not retroactively scan what is already deployed, and they miss changes made outside your IaC pipeline. Continuous scanning closes that gap. Lensix runs the vpc_opencassandra check on a schedule so a manually edited rule or a drifted resource surfaces in your dashboard rather than in someone's breach report.
Best practices
- No public IPs on data nodes. Cassandra nodes should sit on internal-only addresses. Use Cloud NAT for outbound and IAP for admin access.
- Default deny. Build your VPC firewall around an implicit deny and open only the specific ports and source ranges each tier needs.
- Enable authentication and TLS. Set
PasswordAuthenticatorand enable internode encryption so port 7001 is doing its job. A firewall is one layer, not the only layer. - Tag your resources. Use network tags like
cassandra-nodeso firewall rules target specific instances rather than the whole network. - Audit source ranges quarterly. Broad ranges creep in over time as people troubleshoot and forget to revert. Review them on a cadence.
- Keep backups you can actually restore. The strongest defense against a ransom event is a tested restore process.
Exposing Cassandra to the internet is a five-minute mistake that can become a very expensive one. Scope your firewall rules tightly, gate changes in CI, and scan continuously so that a public port 7001 never lives long enough to be found.

