Back to blog
Best PracticesCloud SecurityGCPMonitoring & LoggingNetworking

Subnet VPC Flow Logs Disabled: Why It Matters and How to Fix It

Learn why GCP subnets without VPC Flow Logs are a security blind spot, how to enable logging with gcloud and Terraform, and how to enforce it org-wide.

TL;DR

This check flags GCP VPC subnets that have flow logs turned off, which leaves you blind to network traffic during incident response and traffic analysis. Enable flow logs on the subnet with gcloud compute networks subnets update --enable-flow-logs and tune the sampling rate to balance cost against coverage.

VPC Flow Logs record a sample of the network traffic moving through your subnets: who talked to whom, on what port, how many bytes, and whether the connection was allowed or denied. When a subnet has them disabled, that traffic happens silently. If something goes wrong, a compromised VM beaconing out to a command-and-control server, an internal service scanning your network, or a data exfiltration attempt, you have no record of it.

The Subnet VPC Flow Logs Disabled check (vpc_noflowlogs) scans your GCP project for any subnet where flow logging is not enabled and surfaces it so you can decide whether that gap is acceptable.


What this check detects

Each subnet in a GCP VPC has a flow logs setting that is off by default. The check inspects the logConfig property of every subnet in scope and reports the ones where enableFlowLogs is false or absent.

Flow logs operate at the subnet level, not the VPC level. That distinction trips people up. You can have flow logs enabled on three subnets and forgotten on a fourth, and that fourth subnet is exactly where an attacker prefers to operate. The check evaluates each subnet independently so a single overlooked subnet does not hide behind its well-configured neighbors.

Note: VPC Flow Logs only capture traffic for VMs, GKE nodes, and other instances attached to a subnet. They do not log traffic to Google-managed services that bypass the subnet data path, and they do not replace audit logs. Think of them as a network-layer record, complementary to Cloud Audit Logs at the control plane.


Why it matters

Network visibility is one of those things you do not miss until you need it, and by then it is too late to turn on retroactively. Flow logs cannot record traffic that already happened.

Incident response goes dark

Say a VM in a subnet without flow logs gets compromised through an exposed service. Your security team wants to answer basic questions: What did this host connect to? Did it move laterally to other instances? Was data sent to an external IP? Without flow logs, those answers do not exist. You are reduced to guessing based on whatever logs the application itself happened to write.

Detection of lateral movement and exfiltration

Flow logs feed detection pipelines. Tools that watch for unusual east-west traffic, connections to known-bad IP ranges, or sudden spikes in outbound bytes all depend on the flow data being there. A subnet without logging is a detection blind spot, and attackers who do reconnaissance will gravitate toward the segments where they are least likely to be seen.

Compliance and audit gaps

Frameworks like PCI DSS, SOC 2, and the CIS Google Cloud Benchmark expect network traffic to be logged and retained. CIS GCP control 3.9 specifically calls for VPC Flow Logs to be enabled. An auditor who finds production subnets with logging disabled will write it up, and remediating after the fact does not recover the months of missing data.

Warning: Flow logs are not free. You pay for log generation and for storage in Cloud Logging. A busy subnet sampling at 100 percent can generate significant volume. Plan your sampling rate and log retention before enabling logging fleet-wide, or the bill will surprise you.


How to fix it

Enabling flow logs on an existing subnet is a non-disruptive change. It does not affect routing or traffic flow, it just starts recording.

Using the gcloud CLI

Enable flow logs on a specific subnet:

gcloud compute networks subnets update SUBNET_NAME \
  --region=REGION \
  --enable-flow-logs

For production, you almost always want to tune the log configuration rather than accept defaults. The defaults sample 50 percent of flows with a 5 second aggregation interval, which can be more data than you need:

gcloud compute networks subnets update SUBNET_NAME \
  --region=REGION \
  --enable-flow-logs \
  --logging-flow-sampling=0.5 \
  --logging-aggregation-interval=interval-5-sec \
  --logging-metadata=include-all

A few notes on those flags:

  • --logging-flow-sampling takes a value from 0.0 to 1.0. Lower values reduce cost but capture fewer flows. For most workloads, 0.5 is a reasonable starting point, and high-security subnets may justify higher.
  • --logging-aggregation-interval controls how flows are batched. Longer intervals (up to interval-15-min) reduce volume but lower granularity.
  • --logging-metadata can be include-all, exclude-all, or a custom field list. Excluding metadata cuts log size considerably.

Using the Google Cloud Console

  1. Go to VPC network → VPC networks and select the network containing the subnet.
  2. Click the subnet name, then Edit.
  3. Set Flow logs to On.
  4. Expand Configure logs to set the sampling rate, aggregation interval, and metadata options.
  5. Click Save.

Using Terraform

If you manage your network as code, add a log_config block to the subnet resource. This is the durable fix, because it stops the setting from drifting back off:

resource "google_compute_subnetwork" "app_subnet" {
  name          = "app-subnet"
  region        = "us-central1"
  network       = google_compute_network.vpc.id
  ip_cidr_range = "10.0.1.0/24"

  log_config {
    aggregation_interval = "INTERVAL_5_SEC"
    flow_sampling        = 0.5
    metadata             = "INCLUDE_ALL_METADATA"
  }
}

Tip: To enable flow logs across many subnets at once, loop over the output of gcloud compute networks subnets list. Filter to the regions and networks you care about, then run the update command for each. Pair this with the sampling settings your cost budget allows so you are not enabling 100 percent sampling everywhere by accident.


How to prevent it from happening again

Fixing the subnets you have today does nothing for the subnet someone creates next week. Prevention belongs in your provisioning pipeline and your policy layer.

Enforce it with Organization Policy

GCP offers a built-in org policy constraint that forces flow logs on at subnet creation. Apply it at the organization or folder level so it covers everything beneath:

gcloud resource-manager org-policies enable-enforce \
  compute.requireVpcFlowLogs \
  --organization=ORGANIZATION_ID

With this constraint enforced, any attempt to create a subnet without flow logs is rejected. This is the strongest control because it closes the gap at the API level, not after the fact.

Add a policy-as-code gate in CI/CD

If your infrastructure flows through Terraform, catch the problem before it reaches GCP. A Conftest or OPA policy can fail the plan when a subnet lacks a log_config block:

package main

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "google_compute_subnetwork"
  not resource.change.after.log_config
  msg := sprintf("Subnet '%s' must have flow logs enabled (log_config block)", [resource.address])
}

Wire this into your pull request checks so the build goes red before anyone merges a non-compliant subnet.

Tip: Continuous scanning closes the loop between prevention and reality. Lensix re-runs the vpc_noflowlogs check on a schedule, so even if a subnet slips past your gates through a manual console change or an emergency hotfix, you find out quickly rather than during the next audit.


Best practices

  • Enable flow logs on every production subnet. The cost of logging is small next to the cost of a blind incident response. Reserve the off setting for short-lived test subnets where the data has no value.
  • Tune sampling per subnet, not per fleet. A subnet hosting your payment processing deserves higher sampling than a batch-processing subnet that moves predictable bulk data.
  • Route logs somewhere durable. By default flow logs land in Cloud Logging, where they age out with your retention settings. For long-term retention and analysis, set up a log sink to BigQuery or Cloud Storage.
  • Exclude metadata you do not analyze. If your detection tooling only uses the five-tuple and byte counts, set metadata to exclude-all and cut your log volume substantially.
  • Treat the subnet as the unit of policy. Because logging is configured per subnet, your audits, dashboards, and alerts should also operate per subnet so a single quiet exception does not hide in an aggregate.
  • Combine flow logs with Cloud Audit Logs. Flow logs tell you what moved on the network; audit logs tell you who changed the configuration. You need both to reconstruct an incident.

VPC Flow Logs are one of the cheapest forms of insurance in your cloud account. Turning them on costs a few cents and a config change. Leaving them off costs nothing until the day you need to answer a question the logs would have answered, and then it costs everything.