Back to blog
Best PracticesCloud SecurityDatabasesGCPNetworking

Firewall Allows Public Redis: Closing an Open Door on GCP

Learn why a GCP firewall rule exposing Redis on port 6379 is a critical risk, how to lock it down with gcloud and Terraform, and how to prevent it returning.

TL;DR

This check flags GCP firewall rules that expose Redis (port 6379) to public source ranges like 0.0.0.0/0. An open Redis instance is one of the fastest ways to get your data stolen or your server hijacked for crypto mining. Lock the rule down to known internal CIDRs and require authentication.

Redis is fast, simple, and trusting by default. That last trait is exactly what makes it dangerous when a firewall rule leaves port 6379 wide open to the internet. The Lensix vpc_openredis check scans your GCP VPC firewall rules and raises a finding when any rule permits inbound traffic to Redis from a public source range.

If you are running Redis on a Compute Engine instance and someone has cracked open the firewall, this is the kind of thing you want to know about before an attacker does.


What this check detects

The check inspects all firewall rules in your GCP project and looks for two conditions in combination:

  • The rule allows ingress traffic on TCP port 6379 (the default Redis port), or a range that includes it.
  • The sourceRanges include a public CIDR such as 0.0.0.0/0, or any range that is not restricted to private internal address space.

When both are true, the rule lets anyone on the internet attempt a connection to your Redis service. A rule like this is the trigger:

{
  "name": "allow-redis-public",
  "direction": "INGRESS",
  "allowed": [
    { "IPProtocol": "tcp", "ports": ["6379"] }
  ],
  "sourceRanges": ["0.0.0.0/0"],
  "targetTags": ["redis"]
}

Note: This check applies to self-managed Redis running on Compute Engine or GKE nodes. If you use Memorystore for Redis, Google manages the network exposure for you and instances are not directly internet-reachable, though you should still audit any port forwarding or bastion setups around them.


Why it matters

Redis was designed to run inside a trusted network. Out of the box, older versions ship with no authentication at all, and even current versions are frequently deployed without a password because "it's just an internal cache." Pair that assumption with a public firewall rule and you have handed control of the database to the internet.

This is not theoretical. Internet-wide scanners hit every open 6379 port within minutes. Here is what an attacker does once they connect:

  • Reads and dumps your data. A single KEYS * followed by GET calls exfiltrates session tokens, cached credentials, and anything else you stored.
  • Writes a malicious cron job or SSH key. Redis can persist its dataset to disk. Attackers abuse CONFIG SET dir and CONFIG SET dbfilename to write a file into /root/.ssh/authorized_keys or /etc/cron.d, giving them shell access to the host.
  • Loads malicious modules. The MODULE LOAD command can pull in a shared object and execute arbitrary code, a common path to crypto miners and botnet membership.
  • Wipes everything. The infamous "ransom" attacks run FLUSHALL and leave a key demanding payment to restore data you no longer have.

Danger: An unauthenticated, publicly exposed Redis instance should be treated as already compromised. If this check fires on a production host, assume an attacker may have established persistence. Rotate any credentials stored in or near Redis and inspect the host for unexpected SSH keys, cron entries, and processes before closing the ticket.


How to fix it

The fix has two layers: close the network exposure first, then make sure Redis itself is not relying on the firewall as its only defense.

1. Find the offending rule

List firewall rules that touch port 6379:

gcloud compute firewall-rules list \
  --filter="allowed.ports:6379" \
  --format="table(name, sourceRanges.list(), allowed[].map().firewall_rule().list(), targetTags.list())"

Confirm which rule has a public source range. Inspect a specific rule in detail:

gcloud compute firewall-rules describe allow-redis-public

2. Restrict the source range

Update the rule so only your application subnet or known internal CIDRs can reach Redis. Replace the example range with your actual VPC subnet:

gcloud compute firewall-rules update allow-redis-public \
  --source-ranges="10.0.0.0/16"

Warning: Narrowing the source range will immediately drop connections from any client outside the new range. Before you apply this, confirm which services legitimately connect to Redis so you do not break a worker or API that happens to call in from a different subnet.

If the rule exists only to expose Redis publicly and nothing should reach it from outside the VPC, delete it entirely:

Danger: Deleting a firewall rule is immediate and affects live traffic. Verify the rule name and check that no internal traffic depends on this allow rule before running the command.

gcloud compute firewall-rules delete allow-redis-public

3. Add authentication and bind correctly

The firewall is your perimeter, not your only control. Harden Redis itself so a future misconfiguration is not catastrophic.

Set a strong password in redis.conf:

# In /etc/redis/redis.conf
requirepass "use-a-long-random-secret-here"
# Bind to the private interface only, never 0.0.0.0
bind 10.0.1.5 127.0.0.1
protected-mode yes

For Redis 6 and later, prefer ACL users over a single shared password:

redis-cli ACL SETUSER appuser on '>strongpassword' ~app:* +@read +@write

Rename or disable dangerous commands so even an authenticated foothold is limited:

# In redis.conf
rename-command CONFIG ""
rename-command FLUSHALL ""
rename-command MODULE ""

Restart Redis to apply the configuration:

sudo systemctl restart redis-server

How to prevent it from happening again

Manually fixing the rule solves today's problem. Policy enforcement stops it from coming back next sprint when someone copies a Terraform module.

Codify firewall rules in Terraform

Define rules with explicit, reviewable source ranges instead of letting people click through the console:

resource "google_compute_firewall" "redis_internal" {
  name      = "allow-redis-internal"
  network   = google_compute_network.main.id
  direction = "INGRESS"

  allow {
    protocol = "tcp"
    ports    = ["6379"]
  }

  source_ranges = ["10.0.0.0/16"]
  target_tags   = ["redis"]
}

Gate it in CI/CD with policy-as-code

Use a tool like Checkov or OPA to fail any plan that exposes 6379 publicly. A simple Conftest policy:

package main

deny[msg] {
  rule := input.resource.google_compute_firewall[name]
  rule.source_ranges[_] == "0.0.0.0/0"
  port := rule.allow[_].ports[_]
  port == "6379"
  msg := sprintf("Firewall '%s' exposes Redis to the public internet", [name])
}

Wire this into your pipeline so a pull request cannot merge a public Redis rule:

terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
conftest test plan.json --policy policy/

Tip: Pair the CI gate with a continuous scan in Lensix. CI catches what flows through your pipeline, but it will not catch a rule someone creates by hand in the console during an incident. Continuous detection closes that gap and alerts you within minutes of a public Redis rule appearing.

Enforce an org policy

You can block public ingress at the organization level so individual project owners cannot create wide-open rules in the first place. Combine VPC Service Controls and constraints like constraints/compute.vpcExternalIpv6 and hierarchical firewall policies that deny public ingress on sensitive ports by default, then allow exceptions explicitly.


Best practices

  • Never expose data stores to the internet. Redis, Memcached, MongoDB, PostgreSQL, and friends belong on private networks. Reach them through a bastion, VPN, or IAP tunnel.
  • Use IAP for TCP forwarding when an engineer needs ad hoc access, instead of opening a firewall rule. Run gcloud compute start-iap-tunnel INSTANCE 6379 --local-host-port=localhost:6379 and tear it down when finished.
  • Prefer Memorystore for production Redis when you can. It removes host-level patching, keeps the instance off the public internet, and supports in-transit encryption.
  • Default deny. Build your firewall posture so everything is blocked unless explicitly allowed, with named, narrowly scoped rules.
  • Always set a password. Treat requirepass or ACLs as mandatory, not optional, even on internal instances. Defense in depth means the perimeter is never your last line.
  • Audit regularly. Source ranges drift over time as networks grow. Schedule recurring reviews so a 10.0.0.0/8 that started reasonable does not quietly become too broad.

The pattern here generalizes well beyond Redis. Any time a firewall rule combines a sensitive service port with a public source range, you are one config mistake away from a breach. Close the perimeter, authenticate the service, and enforce both in code so the fix sticks.