Geolocation

View as Markdown

Platform

runZero resolves a geographic location for every asset where it has enough information to do so, and uses those locations to power the World Map, inventory search, and exports. This page describes the different sources runZero uses for asset geolocation, how user-supplied location tags are interpreted, and the order in which sources are applied.

Where locations come from

runZero builds asset locations from five independent sources during each analysis pass. Every location is recorded with provenance, so each pin on the World Map can be traced back to the specific attribute, integration, or tag that produced it.

SourceDescription
attribute-coordPaired numeric latitude/longitude attributes from integrations or imports.
attribute-ipEgress / public IP addresses resolved through ((MaxMind)) ((GeoLite2)).
attribute-textDiscrete country / city attributes, plus free-form snmp.sysLocation-style strings.
cloud-regionAWS, Azure, GCP, OCI, IBM Cloud, and DigitalOcean region codes resolved to a region centroid.
geolite-isp((GeoIP)) lookup of the asset's primary scanned IP through ((MaxMind)) ((GeoLite2)).
manualUser-supplied geo* asset tags.

An asset can carry locations from more than one source at a time. For example, a cloud workload may have a cloud-region location from its AWS region, an attribute-ip location from its public NAT address, and a manual location set by a tag β€” all three appear as separate pins on the World Map, each labelled with its source.

When multiple sources agree on the same coordinate the entry is de-duplicated.

GeoIP lookups against MaxMind

runZero ships with the MaxMind GeoLite2 City and ASN databases. These are used to resolve any public IP address that runZero observes for an asset into a latitude, longitude, country, subdivision (state/province), city, postal code, timezone, continent, ASN number, and ASN organization name.

Private RFC1918 and RFC6598 addresses are rejected by the lookup layer, so a private IP never produces a location.

Primary and hinted external IPs

When an asset is scanned, runZero records the public IP it observed for that asset. The primary scanned address is looked up directly against GeoLite2 and produces a location with source geolite-isp.

When passive sources or integrations report additional public addresses for the same asset β€” for example a secondary NAT address, or an alternate egress on a multi-homed device β€” those are also looked up. The resulting locations are recorded alongside the primary so that an asset visible at two different egress points appears in both places on the World Map.

Egress and public-IP attributes from integrations

Many integrations report the public / external / NAT IP address an asset was observed from. runZero ingests these and resolves each through GeoLite2. The lookup produces both a city-level location and an ASN annotation for the pin.

The attributes consumed by the egress IP pipeline are:

Attribute Set by
externalIP CrowdStrike, SentinelOne
publicIP Azure (VM/database/load balancer), Microsoft Defender for Endpoint, AWS
publicIPs AWS
natIP Google Cloud Platform
wanIPAddresses Google Workspace
discover.externalIP CrowdStrike

The full set of unique public IPs seen across these attributes is also written back to the asset as an egressIPs attribute, so you can query the underlying values directly.

Cloud region codes

When an integration provides a cloud region code β€” for example AWS us-east-1, Azure eastus, or GCP europe-west4 β€” runZero maps the code to the published centroid of that region. This gives the asset a country, subdivision (where applicable), city, and continent without requiring a GeoIP lookup.

The cloud region pipeline reads from attributes including region, cloud.region, aws.region, azure.region, azure.location, gcp.region, gcp.zone, oci.region, availabilityZone, availability_zone, zone, placement.region, and placement.availabilityZone. Unknown values (for example a generic region=Northeast tag) are ignored.

Discrete country and city attributes

Some integrations report location as separate country (or countryCode) and city fields. runZero pairs these up and resolves the combination to the matching GeoNames city centroid. If only a city is present, the global highest-population match is used.

The country fields consumed are: country, countryCode, country_code, host.country, host.countryCode, host.location.country, host.location.countryCode, discover.country, discover.countryCode, custom.country, and site.country.

The city fields consumed are: city, host.city, host.location.city, discover.city, custom.city, and site.city.

Free-form location strings

Free-form location strings from SNMP and integrations are parsed best-effort. The parser strips address noise β€” house numbers, suite/floor markers, PO boxes, postal codes, street suffixes like St, Ave, Blvd β€” and matches the remaining trailing tokens against the bundled GeoNames tables.

The free-form attributes consumed are: location, host.location, site.location, custom.location, location.address, snmp.sysLocation, and shodan.snmp.location.

This is best-effort by design. SNMP sysLocation has no standardized format, and many devices report a campus or rack identifier rather than an address. When the parser cannot anchor the string to a known city, region, or country, no location is recorded.

Manually setting an asset location

You can pin an asset to a specific geographic location by setting one of the geo* tags below. Each tag has a fixed shape, and the value tells runZero where the asset is. The location appears on the World Map, in exports, and in queries the next time metrics are recalculated for the asset.

Manual geo* tags do not take effect immediately. They are picked up the next time runZero recalculates metrics for the asset, which happens automatically as part of normal task processing (scans, integration syncs, and scheduled metrics tasks). To force the change to apply right away, go to Dashboard β†’ Recalculate metrics.

TL;DR β€” set one tag. Use / to separate fields.

geoCity = Austin/TX/US
geoCity = Springfield/IL/US
geoLatLng = 30.2672/-97.7431

Available tags

Tag Shape Example
geoLatLng lat/lng geoLatLng = 30.2672/-97.7431
geoContinent continent name or two-letter alias (EU, NA, …) geoContinent = Europe
geoCountry country (see Country values) geoCountry = US
geoRegionCountry region/country geoRegionCountry = TX/US
geoRegion region/country or a single token (state, country, or continent) geoRegion = Texas
geoState alias of geoRegion geoState = TX/US
geoProvince alias of geoRegion geoProvince = Ontario
geoCity city/country or city/region/country geoCity = Austin/US

You only need to set one tag per asset. If you set more than one, runZero uses whichever tags match their shape. Tags whose values do not match their expected shape are silently ignored β€” runZero will not guess.

When to use which tag

  • Use geoLatLng if you have exact coordinates from a CMDB, building floor plan, or GPS source.
  • Use geoContinent when you only know the continent.
  • Use geoCountry when you only know the country.
  • Use geoRegionCountry when you know the country and the state/province/region but not the city.
  • Use geoRegion (or its synonyms geoState / geoProvince) when you want runZero to accept any plausible region-ish value: a region/country pair, a unique state name (Texas, Ontario, Bavaria), a country code, or a continent.
  • Use geoCity in every other case. The two-field form is enough for major cities; use the three-field form to disambiguate names like Springfield, Portland, or Cambridge.

Field separator

The separator between fields is always a forward slash (/). The characters -, ., ,, and _ are not field separators because they appear inside real city and region names β€” Winston-Salem, St. Louis, Stratford-upon-Avon, St-Lawrence.

geoCity = Austin/US                   βœ“  city/country
geoCity = Austin TX US                βœ—  no separators
geoCity = Austin-TX-US                βœ—  hyphen is part of names, not a separator
geoCity = Austin,TX,US                βœ—  comma is part of names, not a separator

If you set a tag through the UI or API and the value contains spaces, runZero stores those spaces as underscores. The parser treats _ and a space identically inside a field, so geoCity = San Francisco/CA/US and geoCity = San_Francisco/CA/US parse identically.

Country values

Any of these forms work for the country field:

Form Examples
ISO 3166-1 alpha-2 US, DE, GB, JP
ISO 3166-1 alpha-3 USA, DEU, GBR, JPN
English name United States, Germany, Japan
Common alias UK and Britain (both β†’ GB)

Country values are case-insensitive. When an alias is recognized, runZero normalizes it to the ISO alpha-2 code shown on the map.

Region values

Region values are state, province, or admin region names. runZero recognizes both short codes and full names for the countries below; for other countries, runZero accepts the GeoNames admin1 code directly (often a numeric value like 02 or 16).

Country Examples of accepted region values
United States TX, Texas, CA, California
Canada ON, Ontario, BC, British Columbia, QuΓ©bec
Australia NSW, New South Wales, VIC, Victoria
United Kingdom England, Scotland, Wales, Northern Ireland
Ireland Connacht, Leinster, Munster, Ulster
New Zealand Auckland, Canterbury, Wellington

If runZero does not recognize the region, the asset still resolves at the country level β€” the region tag is informative but never blocking.

City matching and GeoNames

City and region matches are performed against the bundled GeoNames data. The matcher is fuzzy: St. Louis, St Louis, St-Louis, Saint Louis, and saint_louis all resolve to the same record. The canonical GeoNames spelling is what shows on the map and in exports, so your tag values do not need to be perfectly formatted to look right.

When a city name is ambiguous (Springfield, Cambridge, Portland), use the three-field form to disambiguate:

geoCity = Springfield/IL/US      βœ“ disambiguated
geoCity = Springfield/MO/US      βœ“ different city
geoCity = Springfield/US         ⚠ resolves to whichever Springfield is largest

Examples

Pinning a corporate office:

geoCity = Austin/TX/US

A device with exact coordinates:

geoLatLng = 30.2672/-97.7431

A subnet known to be in Germany but unknown city:

geoCountry = DE

A device in a region but unknown city:

geoRegionCountry = Bayern/DE

What happens if the value is wrong?

Each tag has a fixed shape and a strict matcher. When the value does not fit the shape β€” or names a place that runZero’s bundled GeoNames data does not recognize β€” the tag produces no manual location, and no manual pin is shown on the map for that asset.

This is intentional. To debug:

  1. Confirm the field separator is /, not -, ., or ,.
  2. Confirm the country value resolves (try the ISO alpha-2 code).
  3. For geoCity, try the three-field form to disambiguate the city.
  4. As a last resort, use geoLatLng with explicit coordinates.

Searching by location in the asset inventory

The asset inventory supports a geo keyword (with synonyms geo_within and geo_radius) that matches assets whose geolocation falls inside a circular area:

geo:<lat>,<lon>[,<radius>]
  • <lat> and <lon> are decimal degrees (30.2672,-97.7431).
  • <radius> is optional and defaults to 50 km. Supply a number followed by km, mi, or m (for example 25km, 15mi, 5000m). Plain numbers are treated as kilometres.
  • The radius is clamped between 1 metre and 1,000 km.

Examples:

geo:30.2672,-97.7431              # within 50 km of downtown Austin
geo:30.2672,-97.7431,25km         # within 25 km
geo:52.5200,13.4050,100mi         # within 100 miles of Berlin
geo_within:51.5074,-0.1278,5km    # synonym

Match is true if any location source on the asset falls inside the circle. This means a workload with both a cloud region centroid and a public IP egress in the same metro area matches the same geo: query.

The same geo: keyword is available on the services inventory.

When locations are refreshed

Asset locations are recalculated on every analysis pass. Each source’s previously recorded locations are replaced by the new ones, so stale data β€” for example a cloud-region attribute that an integration stopped reporting β€” is removed automatically on the next pass.

If you change a geo* tag value, the new location will appear on the next analysis pass and not before.

Updated