| 1 | <!--startmeta |
| 2 | custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/crates/netflow-plugin/integrations/netbox.md" |
| 3 | meta_yaml: "https://github.com/netdata/netdata/edit/master/src/crates/netflow-plugin/metadata.yaml" |
| 4 | sidebar_label: "NetBox" |
| 5 | learn_status: "Published" |
| 6 | learn_rel_path: "Network Flows/Enrichment Methods" |
| 7 | keywords: ['netbox', 'ipam', 'dcim', 'source of truth', 'prefix list', 'network identity'] |
| 8 | message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE FLOWS' metadata.yaml FILE" |
| 9 | endmeta--> |
| 10 | |
| 11 | <!-- markdownlint-disable-file --> |
| 12 | |
| 13 | # NetBox |
| 14 | |
| 15 | |
| 16 | <img src="https://netdata.cloud/img/network-wired.svg" width="150"/> |
| 17 | |
| 18 | |
| 19 | Plugin: netflow-plugin |
| 20 | Module: netbox |
| 21 | |
| 22 | <img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> |
| 23 | |
| 24 | ## Overview |
| 25 | |
| 26 | Annotate network flows with tenant, site, role, VRF, and description metadata |
| 27 | from NetBox. [NetBox](https://github.com/netbox-community/netbox) is the most |
| 28 | widely deployed open-source IPAM / DCIM. It is Apache-2.0 licensed and maintained |
| 29 | by the netbox-community organization (commercial variants -- NetBox Cloud and |
| 30 | NetBox Enterprise -- are offered by NetBox Labs on top of the same upstream code). |
| 31 | Operators already curate prefix metadata in NetBox and want flow records to |
| 32 | inherit those labels automatically rather than maintaining a parallel list in |
| 33 | `netflow.yaml`. |
| 34 | |
| 35 | This integration polls NetBox's Prefixes REST API at a configurable interval, |
| 36 | transforms the response with jq, and labels matching flow prefixes with whatever |
| 37 | fields you map. NetBox is the authoritative source -- when the same prefix is |
| 38 | tagged in NetBox and in the static `networks:` block, the static block wins |
| 39 | (operator override is intentional, see the |
| 40 | [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment) |
| 41 | concept page). |
| 42 | |
| 43 | Use cases: applying your organisation's data-centre rack labels, tenant names, |
| 44 | environment tags (prod / staging / dev), and VRF / site identifiers to flows so |
| 45 | dashboards and queries surface "this is the staging tier in fra1" instead of a |
| 46 | raw CIDR. |
| 47 | |
| 48 | |
| 49 | Periodic HTTPS GET to `/api/ipam/prefixes/` on your NetBox host. Authentication is |
| 50 | a NetBox API token in the `Authorization` header. NetBox supports two token |
| 51 | formats: |
| 52 | |
| 53 | - **Legacy v1 tokens** (`Authorization: Token <token>`) -- accepted by all NetBox |
| 54 | versions, simplest to wire up. |
| 55 | - **v2 tokens** (NetBox 4.5+, `Authorization: Bearer nbt_<12-char-key>.<40-char-token>`) -- |
| 56 | the prefix `nbt_`, the token key, a dot, and the token secret are all part of |
| 57 | the header value. |
| 58 | |
| 59 | The plugin transports either format -- the value is whatever NetBox issued for the |
| 60 | service account. |
| 61 | |
| 62 | The plugin runs the configured `transform` (jaq -- a jq-equivalent) over the |
| 63 | parsed JSON body and produces per-prefix objects. NetBox's response is paginated; |
| 64 | the plugin does **not** follow `next` links. Pass `?limit=0` (NetBox default |
| 65 | `MAX_PAGE_SIZE` is 1000; setting `0` removes the cap when the server config |
| 66 | allows) or an explicit `?limit=N` greater than your prefix count, or expose a |
| 67 | server-side aggregator that returns the full list at one URL. |
| 68 | |
| 69 | |
| 70 | This integration is only supported on the following platforms: |
| 71 | |
| 72 | - Linux |
| 73 | |
| 74 | This integration supports multiple instances configured side-by-side. |
| 75 | |
| 76 | |
| 77 | ### Default Behavior |
| 78 | |
| 79 | #### Auto-Detection |
| 80 | |
| 81 | Disabled by default. Add an entry under `enrichment.network_sources` with your NetBox URL and API token. |
| 82 | |
| 83 | #### Limits |
| 84 | |
| 85 | Resource use scales with the number of NetBox prefixes returned by the URL and transform. Use NetBox filtering when you only need a subset of VRFs, sites, tenants, or roles. |
| 86 | |
| 87 | #### Performance Impact |
| 88 | |
| 89 | One HTTP request per refresh interval plus a jq transform over the response. Runtime enrichment does prefix matching for source and destination IPs, and cost scales with the number of loaded network-source records. |
| 90 | |
| 91 | ## Setup |
| 92 | |
| 93 | |
| 94 | ### Prerequisites |
| 95 | |
| 96 | #### NetBox API token with read scope on Prefixes |
| 97 | |
| 98 | In NetBox, create or reuse a service-account user, then generate an API token |
| 99 | under "Admin > Users > Tokens". Restrict the token to read-only and (for |
| 100 | NetBox 4.x) limit the scope to `ipam.view_prefix`. The token value goes in the |
| 101 | `Authorization` header. |
| 102 | |
| 103 | The plugin only reads -- never writes -- so a read-only token is sufficient |
| 104 | and recommended. Token format depends on the NetBox version: |
| 105 | |
| 106 | - NetBox 3.x or earlier: `Token <40-char-hex>` (legacy). |
| 107 | - NetBox 4.0 through 4.4: legacy `Token <hex>`. |
| 108 | - NetBox 4.5+: legacy `Token <hex>` or new |
| 109 | `Bearer nbt_<12-char-key>.<40-char-token>` (v2 tokens). |
| 110 | |
| 111 | |
| 112 | #### Bulk endpoint (`?limit=0` or aggregator) |
| 113 | |
| 114 | The plugin fetches a single page. NetBox's default `PAGINATE_COUNT` is 50 |
| 115 | and `MAX_PAGE_SIZE` is 1000. For inventories above 1000 prefixes, either |
| 116 | raise `MAX_PAGE_SIZE` server-side and pass `?limit=0`, or expose an internal |
| 117 | aggregator endpoint that walks pagination and returns the full list at one URL. |
| 118 | |
| 119 | |
| 120 | #### NetBox version-aware field mapping |
| 121 | |
| 122 | NetBox **4.2** replaced the per-prefix `site` foreign key with a generic |
| 123 | `scope` field (a prefix can now be scoped to a region, site group, site, or |
| 124 | location -- not just a site). API responses on 4.2+ omit `site` and expose |
| 125 | `scope` (read-only) plus `scope_type` / `scope_id`. Adjust your jq accordingly |
| 126 | -- on 4.2+ use `(.scope.name // "")`, on 4.1 and earlier use |
| 127 | `(.site.name // "")`. |
| 128 | |
| 129 | |
| 130 | |
| 131 | ### Configuration |
| 132 | |
| 133 | #### Options |
| 134 | |
| 135 | Add a named entry under `enrichment.network_sources` pointing at your NetBox. |
| 136 | The network source configuration accepts `url`, `method`, |
| 137 | `headers`, `proxy`, `tls`, `timeout`, `interval`, and `transform`. Authentication |
| 138 | is configured via the generic `headers:` map -- there is no NetBox-specific |
| 139 | auth helper. |
| 140 | |
| 141 | |
| 142 | <details open><summary>Config options</summary> |
| 143 | |
| 144 | |
| 145 | |
| 146 | | Option | Description | Default | Required | |
| 147 | |:-----|:------------|:--------|:---------:| |
| 148 | | url | NetBox prefixes API endpoint, including `?limit=` (recommend `?limit=0` for full inventory in one shot when the server's `MAX_PAGE_SIZE` allows it). | | yes | |
| 149 | | headers.Authorization | NetBox API token. Use `Token <hex>` for legacy v1 or `Bearer nbt_<12-char-key>.<40-char-token>` for v4.5+ v2 tokens. | | yes | |
| 150 | | interval | How often to refresh. NetBox is your source of truth; 5 minutes is typical for IPAMs that change frequently, 1 hour is fine for static inventories. | 60s | no | |
| 151 | | timeout | HTTP request timeout. Bump to 30-60s if your NetBox returns thousands of prefixes in one shot. | 10s | no | |
| 152 | | transform | jq expression mapping NetBox's `.results[]` to per-prefix objects with `prefix` and any of `name`, `role`, `site`, `region`, `country`, `state`, `city`, `tenant`, `asn`, `asn_name`. | . | yes | |
| 153 | | tls.ca_file | Path to your internal CA bundle when NetBox runs behind internal PKI. Disabling verification is rejected by the validator -- use this instead. | | no | |
| 154 | |
| 155 | |
| 156 | </details> |
| 157 | |
| 158 | |
| 159 | |
| 160 | #### via File |
| 161 | |
| 162 | The configuration file name for this integration is `netflow.yaml`. |
| 163 | |
| 164 | |
| 165 | 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 |
| 166 | Netdata [config directory](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration/README.md#locate-your-config-directory). |
| 167 | |
| 168 | ```bash |
| 169 | cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata |
| 170 | sudo ./edit-config netflow.yaml |
| 171 | ``` |
| 172 | |
| 173 | ##### Examples |
| 174 | |
| 175 | ###### NetBox 4.5+ with v2 token, scope-aware mapping |
| 176 | |
| 177 | Standard NetBox 4.2+ wiring. Maps tenant, role, the new `scope` field |
| 178 | (covers site / region / site-group / location), and the human-readable |
| 179 | description. `?limit=0` returns all prefixes in one call when |
| 180 | `MAX_PAGE_SIZE` is set to `0` or `None` on the NetBox server. |
| 181 | |
| 182 | |
| 183 | ```yaml |
| 184 | enrichment: |
| 185 | network_sources: |
| 186 | netbox: |
| 187 | url: "https://netbox.example.internal/api/ipam/prefixes/?limit=0" |
| 188 | headers: |
| 189 | Authorization: "Bearer nbt_<12-char-key>.<40-char-token>" |
| 190 | interval: 5m |
| 191 | timeout: 30s |
| 192 | transform: | |
| 193 | .results[] | { |
| 194 | prefix: .prefix, |
| 195 | tenant: (.tenant.name // ""), |
| 196 | role: (.role.name // ""), |
| 197 | site: (.scope.name // ""), |
| 198 | name: (.description // "") |
| 199 | } |
| 200 | |
| 201 | ``` |
| 202 | ###### NetBox 3.x / 4.0 / 4.1 with legacy site field |
| 203 | |
| 204 | Pre-4.2 NetBox still exposes `site` directly on the Prefix object. Use a |
| 205 | legacy `Token` header and read `.site.name` instead of `.scope.name`. |
| 206 | |
| 207 | |
| 208 | <details open><summary>Config</summary> |
| 209 | |
| 210 | ```yaml |
| 211 | enrichment: |
| 212 | network_sources: |
| 213 | netbox: |
| 214 | url: "https://netbox.example.internal/api/ipam/prefixes/?limit=10000" |
| 215 | headers: |
| 216 | Authorization: "Token abcdef0123456789abcdef0123456789abcdef01" |
| 217 | interval: 15m |
| 218 | transform: | |
| 219 | .results[] | { |
| 220 | prefix: .prefix, |
| 221 | tenant: (.tenant.name // ""), |
| 222 | role: (.role.name // ""), |
| 223 | site: (.site.name // ""), |
| 224 | name: (.description // "") |
| 225 | } |
| 226 | |
| 227 | ``` |
| 228 | </details> |
| 229 | |
| 230 | ###### NetBox behind internal PKI (mTLS) |
| 231 | |
| 232 | When NetBox is fronted by internal PKI. `tls.verify: false` is rejected at |
| 233 | config-load -- supply your CA explicitly and (optionally) a client |
| 234 | certificate. |
| 235 | |
| 236 | |
| 237 | <details open><summary>Config</summary> |
| 238 | |
| 239 | ```yaml |
| 240 | enrichment: |
| 241 | network_sources: |
| 242 | netbox: |
| 243 | url: "https://netbox.example.internal/api/ipam/prefixes/?limit=0" |
| 244 | headers: |
| 245 | Authorization: "Token abcdef0123456789abcdef0123456789abcdef01" |
| 246 | interval: 5m |
| 247 | tls: |
| 248 | enable: true |
| 249 | ca_file: /etc/netdata/ssl/internal-ca.pem |
| 250 | cert_file: /etc/netdata/ssl/netdata.crt |
| 251 | key_file: /etc/netdata/ssl/netdata.key |
| 252 | transform: | |
| 253 | .results[] | { |
| 254 | prefix: .prefix, |
| 255 | tenant: (.tenant.name // ""), |
| 256 | role: (.role.name // ""), |
| 257 | site: (.scope.name // ""), |
| 258 | name: (.description // "") |
| 259 | } |
| 260 | |
| 261 | ``` |
| 262 | </details> |
| 263 | |
| 264 | ###### VRF-aware mapping (multi-tenant networks) |
| 265 | |
| 266 | When the same RFC1918 prefix appears in multiple VRFs, fold the VRF name |
| 267 | into the friendly `name` so dashboards disambiguate. Note: the plugin keys |
| 268 | on `prefix` only -- if two rows share a CIDR, the last one wins. Filter the |
| 269 | NetBox query (`?vrf_id=N`) to scope the export. |
| 270 | |
| 271 | |
| 272 | <details open><summary>Config</summary> |
| 273 | |
| 274 | ```yaml |
| 275 | enrichment: |
| 276 | network_sources: |
| 277 | netbox-prod-vrf: |
| 278 | url: "https://netbox.example.internal/api/ipam/prefixes/?limit=0&vrf_id=12" |
| 279 | headers: |
| 280 | Authorization: "Token abcdef0123456789abcdef0123456789abcdef01" |
| 281 | interval: 5m |
| 282 | transform: | |
| 283 | .results[] | { |
| 284 | prefix: .prefix, |
| 285 | tenant: (.tenant.name // ""), |
| 286 | role: (.role.name // ""), |
| 287 | site: (.scope.name // ""), |
| 288 | name: ((.vrf.name // "default") + ": " + (.description // "")) |
| 289 | } |
| 290 | |
| 291 | ``` |
| 292 | </details> |
| 293 | |
| 294 | |
| 295 | |
| 296 | ### Only first 50 prefixes loaded |
| 297 | |
| 298 | NetBox's default `PAGINATE_COUNT` is 50 and the plugin does not follow `next` |
| 299 | links. Pass `?limit=0` (NetBox removes the cap when `MAX_PAGE_SIZE` is |
| 300 | `0` server-side) or `?limit=N` larger than your inventory. For inventories |
| 301 | above the server's `MAX_PAGE_SIZE` (default 1000), expose a server-side |
| 302 | aggregator endpoint. |
| 303 | |
| 304 | |
| 305 | ### 401 / 403 from NetBox |
| 306 | |
| 307 | Token missing, expired, or wrong format. Verify with one of: |
| 308 | `curl -H "Authorization: Token <legacy-token>" https://netbox/api/ipam/prefixes/` |
| 309 | or |
| 310 | `curl -H "Authorization: Bearer nbt_<12-char-key>.<40-char-token>" https://netbox/api/ipam/prefixes/`. |
| 311 | On NetBox 4.5+ check whether the token is v1 (`Token <hex>`) or v2 |
| 312 | (`Bearer nbt_<12-char-key>.<40-char-token>`) and use the matching header. |
| 313 | A v2 token sent with the legacy `Token` prefix is rejected as an invalid v1 |
| 314 | token. Watch the journal |
| 315 | for `network-sources` warnings -- HTTP errors are logged there as |
| 316 | refresh-failed warnings. |
| 317 | |
| 318 | |
| 319 | ### site is empty after upgrade to NetBox 4.2 |
| 320 | |
| 321 | NetBox 4.2 removed `site` from the Prefix model and replaced it with `scope` |
| 322 | (a generic foreign key that can reference region / site group / site / |
| 323 | location). Update the jq from `(.site.name // "")` to `(.scope.name // "")`. |
| 324 | Alternatively, key on `(.scope.name // .site.name // "")` so the same config |
| 325 | works across the upgrade boundary. |
| 326 | |
| 327 | |
| 328 | ### VRF collisions (same CIDR in multiple VRFs) |
| 329 | |
| 330 | The plugin's network-attributes trie keys on `prefix` only -- there is no VRF |
| 331 | dimension on the flow side. If NetBox lists `10.0.0.0/24` in three VRFs, only |
| 332 | the last row wins. Filter the export with `?vrf_id=N` per data-plane and run |
| 333 | one named source per VRF, or fold the VRF name into the friendly `name` so |
| 334 | dashboards disambiguate. |
| 335 | |
| 336 | |
| 337 | ### Empty result triggers backoff |
| 338 | |
| 339 | An empty `results` array (legitimate state for a freshly-installed NetBox) |
| 340 | is treated as a fetch failure by the cross-cutting source loop and triggers |
| 341 | exponential backoff. Add at least one synthetic prefix (e.g. a `RFC1918` |
| 342 | container) so the response is never empty. |
| 343 | |
| 344 | |
| 345 |