<!--startmeta
custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/crates/netflow-plugin/integrations/gcp_ip_ranges.md"
meta_yaml: "https://github.com/netdata/netdata/edit/master/src/crates/netflow-plugin/metadata.yaml"
sidebar_label: "GCP IP Ranges"
learn_status: "Published"
learn_rel_path: "Network Performance Monitoring/Network Flows/Enrichment Methods"
keywords: ['gcp', 'google cloud', 'google', 'cloud', 'ip ranges', 'cloud.json', 'goog.json', 'prefix list', 'network identity']
message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE FLOWS' metadata.yaml FILE"
endmeta-->

<!-- markdownlint-disable-file -->

# GCP IP Ranges


<img src="https://netdata.cloud/img/network-wired.svg" width="150"/>


Plugin: netflow-plugin
Module: gcp-ip-ranges

<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />

## Overview

Annotate network flows with Google ownership, service, and scope labels from
Google public IP ranges. Google publishes its public IP ranges as two static JSON
files served from `gstatic.com`. Wire one of them as a
`network_source` and the netflow plugin fetches it periodically, transforms each
prefix entry through your jq filter, and merges the resulting CIDR-keyed records
into the network-attributes trie. Flows whose source or destination IP falls
inside a Google-owned prefix are then labeled with `*_NET_TENANT`,
`*_NET_REGION`, `*_NET_ROLE`, etc. according to the labels your transform emits.

Two upstream files exist and they are NOT interchangeable:

- **`https://www.gstatic.com/ipranges/cloud.json`** -- the prefixes used by
  Google Cloud (Compute Engine, GKE, Cloud Run, Cloud Functions, Cloud SQL,
  and the rest of Google Cloud Platform). This is what you almost always want
  for cloud-traffic attribution.
- **`https://www.gstatic.com/ipranges/goog.json`** -- the broader Google IP
  space, including consumer-facing properties (Search, Gmail, YouTube, Google
  Workspace, Maps, Ads, etc.). It is a strict superset of `cloud.json` but
  **carries no service or region metadata** -- only the bare CIDRs.

For the cross-cutting network-identity behavior (merge order with GeoIP and
static config, jq output contract, TLS rules, single-page fetch, failure /
backoff handling), see
[Network Identity](https://github.com/netdata/netdata/blob/master/docs/npm/network-flows/enrichment.md).


Periodic HTTPS GET against the chosen `gstatic.com` URL. The body is parsed
as JSON and the configured `transform` (a [jaq](https://github.com/01mf02/jaq)
jq-equivalent expression) runs over the parsed value. Each output object is
merged into the network-attributes trie keyed on its `prefix` field; remaining
fields (`name`, `role`, `site`, `region`, `country`, `state`, `city`, `tenant`,
`asn`, `asn_name`) populate the corresponding `*_NET_*` flow-record columns
when a flow's IP matches the prefix.

The upstream files are static JSON snapshots, not pageable APIs -- one fetch
per cycle is the whole dataset. Each contains a `syncToken` and a
`creationTime` you can inspect to see when Google last regenerated them.
The plugin fetches the full document on each refresh cycle.


This integration is supported on all platforms.

This integration supports multiple instances configured side-by-side.


### Default Behavior

#### Auto-Detection

Disabled by default. Add an entry under enrichment.network_sources to enable.

#### Limits

One full GCP prefix document is fetched per refresh. Resource use scales with the number of GCP prefixes selected by your transform and the refresh interval.

#### Performance Impact

One short HTTPS GET per `interval`, plus a jq pass over the response.
`cloud.json` is on the order of ~1000 prefix entries and the trie merge
is bounded by that count; runtime cost is negligible against typical flow
ingest. `goog.json` is similar in size.


## Setup


### Prerequisites

#### Outbound HTTPS to gstatic.com

The agent host must be able to reach `https://www.gstatic.com/ipranges/cloud.json`
(or `goog.json`). The files are public CDN-served static JSON; no Google
Cloud project, no service account, no API key, and no IAM permission is
required.


#### Pick the right file for your use case

- Use `cloud.json` to attribute traffic to/from **Google Cloud Platform**
  services (Compute Engine VMs, GKE, Cloud Run, Cloud Functions, Cloud
  SQL, BigQuery API, Pub/Sub, GCS endpoints, etc.). Carries `service` and
  `scope` (region) per prefix.
- Use `goog.json` to also catch **non-cloud Google traffic** (Gmail,
  YouTube, Google Workspace, Search, Ads, Maps, etc.). It carries no
  `service` or `scope` -- you only get "this is Google" attribution.
- Configure both as separate sources if you want both attributions and
  a deterministic merge order between them. Within network-identity, more-
  specific prefixes win at lookup time, so a `cloud.json` match for a
  Compute Engine prefix will out-rank the broader `goog.json` umbrella.



### Configuration

#### Options

Add a named entry under `enrichment.network_sources`. The entry name is
cosmetic (used in logs and metrics); the labels that end up in flow records
come from the fields your `transform` emits.


<details open><summary>Config options</summary>



| Option | Description | Default | Required |
|:-----|:------------|:--------|:---------:|
| url | The Google IP-ranges JSON URL. Use `cloud.json` for GCP services or `goog.json` for the broader Google IP space. | https://www.gstatic.com/ipranges/cloud.json | yes |
| interval | How often to refetch. Google does not publish a fixed cadence; their documentation states the lists are "published and updated frequently". Daily is plenty for most deployments and avoids hammering the CDN. | 60s (loop floor) | no |
| timeout | Per-request timeout. | 60s | no |
| transform | jq expression that converts each entry in `prefixes[]` into an object with a `prefix` field (CIDR string) plus any of the optional label fields (`name`, `role`, `site`, `region`, `country`, `state`, `city`, `tenant`, `asn`, `asn_name`). Required. | . | yes |


</details>



#### via File

The configuration file name for this integration is `netflow.yaml`.


You can edit the configuration file using the [`edit-config`](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration/README.md#edit-configuration-files) script from the
Netdata [config directory](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration/README.md#locate-your-config-directory).

```bash
cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
sudo ./edit-config netflow.yaml
```

##### Examples

###### GCP cloud.json -- tag Google Cloud prefixes by region

Tags every flow whose IP matches a Google Cloud prefix with
`*_NET_TENANT="gcp"`, `*_NET_ROLE="google-cloud"`, and
`*_NET_REGION` set to the GCP scope (`us-central1`, `europe-west1`,
`global`, etc.). Both `ipv4Prefix` and `ipv6Prefix` entries are
covered by the `// (slash-or)` fallback.


```yaml
enrichment:
  network_sources:
    gcp:
      url: "https://www.gstatic.com/ipranges/cloud.json"
      interval: 24h
      timeout: 60s
      transform: |
        .prefixes[] | {
          prefix: (.ipv4Prefix // .ipv6Prefix),
          tenant: "gcp",
          role: "google-cloud",
          region: .scope
        }

```
###### GCP cloud.json -- IPv4 only

Same as above but skips the IPv6 prefixes (some operators only need
IPv4 attribution and prefer to keep the trie smaller).


<details open><summary>Config</summary>

```yaml
enrichment:
  network_sources:
    gcp-v4:
      url: "https://www.gstatic.com/ipranges/cloud.json"
      interval: 24h
      transform: |
        .prefixes[]
        | select(.ipv4Prefix)
        | {
            prefix: .ipv4Prefix,
            tenant: "gcp",
            role: "google-cloud",
            region: .scope
          }

```
</details>

###### Tag a single GCP region

Narrow the source to one region (here `us-central1`) so you can build
dashboards that distinguish that region from the rest of GCP.


<details open><summary>Config</summary>

```yaml
enrichment:
  network_sources:
    gcp-us-central1:
      url: "https://www.gstatic.com/ipranges/cloud.json"
      interval: 24h
      transform: |
        .prefixes[]
        | select(.scope == "us-central1")
        | {
            prefix: (.ipv4Prefix // .ipv6Prefix),
            tenant: "gcp",
            role: "google-cloud",
            region: "us-central1",
            site: "us-central1"
          }

```
</details>

###### Broader Google IP space (goog.json)

Use `goog.json` to also attribute traffic to non-Cloud Google services
(Gmail, YouTube, Workspace, Search, Ads, Maps). The file has no
`service` or `scope` fields, so only `tenant` / `role` are set.
Configure this **alongside** `cloud.json` if you want both -- the more
specific GCP prefixes from `cloud.json` will still win at lookup time.


<details open><summary>Config</summary>

```yaml
enrichment:
  network_sources:
    google-all:
      url: "https://www.gstatic.com/ipranges/goog.json"
      interval: 24h
      transform: |
        .prefixes[] | {
          prefix: (.ipv4Prefix // .ipv6Prefix),
          tenant: "google",
          role: "google"
        }

```
</details>



### cloud.json vs goog.json -- pick the right one

`cloud.json` is the Google Cloud Platform list (Compute Engine, GKE,
Cloud Run, Cloud SQL, BigQuery, GCS, etc.) and carries `service` plus
`scope` (region) per entry. `goog.json` is the broader Google list
(consumer products: Gmail, YouTube, Workspace, Search, Ads, Maps) and
carries **only the bare CIDRs** -- no service, no scope, no region.
Using `goog.json` as if it were `cloud.json` will give you "this is
Google" attribution but no per-region or per-service breakdown. Most
operators want `cloud.json`; some configure both as separate sources.


### No per-service breakdown from cloud.json

Today every entry in `cloud.json` reports `service: "Google Cloud"` --
the file does not split prefixes by individual GCP service (Compute
Engine vs GKE vs Cloud Run, etc.). Region (`scope`) is the dimension
you can actually pivot on. Per-service attribution requires a different
data source.


### Empty result from the transform is treated as failure

If the jq expression yields zero objects (for example, an over-narrow
`select()` that no entry passes), the source backs off as if the fetch
had errored. Check the journal for `network-sources` warnings and verify
your filter against a saved copy of `cloud.json`.


### TLS verification cannot be disabled

`tls.skip_verify: true` (and `tls.verify: false`) are rejected by
validation. `gstatic.com` is publicly trusted so this is rarely an issue
for GCP; if you front the URL through an internal proxy with a private
CA, supply it via `tls.ca_file`.


### Update cadence is not contractual

Google states the lists are "published and updated frequently" but does
not guarantee a fixed cadence. The `syncToken` and `creationTime` keys
at the top of each file let you check when Google last regenerated it.
Daily polling is a safe default; sub-hourly is unnecessary.
