Skip to content

NetBox Integration

NetBox Integration

This document outlines the design for integrating Subnetter with NetBox, enabling bidirectional synchronization of IP address allocations between Subnetter’s planning tool and NetBox’s IPAM capabilities.

Goals

  1. Export Subnetter allocations to NetBox — Push planned network allocations to NetBox as the source of truth
  2. Validate against NetBox — Check for conflicts between planned allocations and existing NetBox data
  3. Import from NetBox — Generate Subnetter configurations from existing NetBox prefixes
  4. Maintain idempotency — Support dry-run mode and incremental updates

Non-Goals (Phase 1)

  • Real-time synchronization
  • NetBox webhooks/event handling
  • Custom field management in NetBox
  • VLAN/VXLAN integration
  • Device/interface assignment

Architecture

Package Structure

packages/
├── netbox/ # New package: @subnetter/netbox
│ ├── src/
│ │ ├── index.ts # Public API exports
│ │ ├── client/
│ │ │ ├── NetBoxClient.ts # HTTP client wrapper
│ │ │ ├── types.ts # NetBox API types
│ │ │ └── endpoints/
│ │ │ ├── prefixes.ts # /api/ipam/prefixes/
│ │ │ ├── aggregates.ts # /api/ipam/aggregates/
│ │ │ ├── sites.ts # /api/dcim/sites/
│ │ │ ├── tenants.ts # /api/tenancy/tenants/
│ │ │ └── roles.ts # /api/ipam/roles/
│ │ ├── export/
│ │ │ ├── exporter.ts # Main export logic
│ │ │ ├── mapper.ts # Subnetter → NetBox mapping
│ │ │ └── diff.ts # Calculate changes
│ │ ├── import/
│ │ │ ├── importer.ts # Main import logic
│ │ │ └── mapper.ts # NetBox → Subnetter mapping
│ │ └── validate/
│ │ └── validator.ts # Conflict detection
│ ├── tests/
│ └── package.json
├── cli/ # Existing CLI package
│ └── src/
│ └── commands/
│ └── netbox.ts # New netbox subcommands

Data Flow

┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Subnetter │ │ @subnetter/ │ │ NetBox │
│ Config (JSON) │────▶│ netbox │────▶│ API │
└─────────────────┘ └──────────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Allocations │ │ Diff/Validate │ │ Prefixes │
│ (CSV) │ │ Engine │ │ Sites │
└─────────────────┘ └──────────────────┘ │ Tenants │
│ Roles │
└─────────────┘

NetBox Object Mapping

Subnetter → NetBox Mapping (NetBox 4.x)

The mapping creates a proper hierarchy that follows NetBox best practices:

NetBox Hierarchy:
├── RIRs (Regional Internet Registries)
│ └── RFC 1918 (private address space)
├── Aggregates (Top-level IP blocks)
│ └── 10.0.0.0/8 (RIR: RFC 1918)
├── Site Groups (Functional grouping - Cloud Providers)
│ ├── Amazon Web Services
│ ├── Microsoft Azure
│ └── Google Cloud Platform
├── Sites (Cloud Regions) - under their respective Site Group
│ ├── us-east-1 (group: Amazon Web Services)
│ ├── eastus (group: Microsoft Azure)
│ ├── us-east1 (group: Google Cloud Platform)
│ └── ...
├── Locations (Availability Zones) - under their respective Site
│ ├── us-east-1a (site: us-east-1)
│ ├── us-east-1b (site: us-east-1)
│ └── ...
└── Prefixes (Subnets) - scoped to their Site
├── 10.100.0.0/26 (scope: us-east-1, tenant: my-account, role: Kubernetes)
└── ...
Subnetter ConceptNetBox ObjectNetBox FieldNotes
Base CIDRAggregateprefix, rirRoot of IP hierarchy (e.g., 10.0.0.0/8)
(auto-created)RIRname, slug, is_privateRFC 1918 for private ranges
Cloud ProviderSite Groupname, slugFunctional grouping: AWS, Azure, GCP
Cloud RegionSitename, slug, groupe.g., us-east-1, under its provider Site Group
Availability ZoneLocationname, slug, sitee.g., us-east-1a, under its Site
Account NameTenantname, slugOrganizational unit
Subnet Type/RoleRolename, sluge.g., Kubernetes, Public, Private
Subnet CIDRPrefixprefix, scope_type, scope_id, tenant, roleScoped to Site (NetBox 4.x)

Key Design Decisions

  1. Aggregates for IP hierarchy root: Aggregates represent the top-level IP blocks you manage (e.g., 10.0.0.0/8 for RFC 1918). This establishes the root of your IP addressing hierarchy in NetBox.

  2. Site Groups for cloud providers: Site Groups are used for functional/logical grouping, which is appropriate for cloud providers. Regions in NetBox are for geographic organization.

  3. Sites for cloud regions: Each cloud region (e.g., us-east-1) is represented as a Site, grouped under its cloud provider’s Site Group.

  4. Locations for availability zones: AZs are represented as Locations within their parent Site.

  5. Scope for prefix-site relationship: In NetBox 4.x, prefixes use scope_type and scope_id to associate with Sites instead of the deprecated site field.

NetBox Prefix Status Mapping

Allocation StateNetBox Status
Planned (from Subnetter)reserved
Deployed (confirmed)active
Deprecateddeprecated

Example NetBox Objects

{
"prefix": "10.0.0.0/8",
"rir": { "name": "RFC1918" },
"description": "Subnetter managed allocation",
"tags": [{ "name": "subnetter-managed" }]
}

CLI Commands

subnetter netbox export

Export Subnetter allocations to NetBox.

Terminal window
subnetter netbox export \
--config config.json \
--netbox-url https://netbox.example.com \
--netbox-token $NETBOX_TOKEN \
[--tenant <name>] # Optional: assign all to specific tenant
[--create-missing] # Create missing sites/tenants/roles
[--dry-run] # Show what would be created/updated
[--format json|table] # Output format for dry-run

Behavior:

  1. Load Subnetter config and generate allocations
  2. Connect to NetBox API
  3. Fetch existing prefixes with subnetter-managed tag
  4. Calculate diff (create, update, delete)
  5. If --dry-run, display changes and exit
  6. Apply changes to NetBox
  7. Report results

Output (dry-run):

NetBox Export Preview
=====================
Will CREATE:
✓ Tenant: ecommerce-production
✓ Site: us-east-1
✓ Site: us-west-2
✓ Role: Public
✓ Role: Private
✓ Prefix: 10.0.0.0/16 (ecommerce-production VPC)
✓ Prefix: 10.0.1.0/24 (us-east-1a Public)
... 58 more prefixes
Will UPDATE:
~ Prefix: 10.0.2.0/24 (description changed)
Will DELETE:
✗ Prefix: 10.0.99.0/24 (no longer in config)
Summary: 62 creates, 1 update, 1 delete
Run without --dry-run to apply changes.

subnetter netbox validate

Check for conflicts between Subnetter config and NetBox.

Terminal window
subnetter netbox validate \
--config config.json \
--netbox-url https://netbox.example.com \
--netbox-token $NETBOX_TOKEN \
[--strict] # Fail on any overlap, even with same tenant

Output:

NetBox Validation Results
=========================
✓ No conflicts with existing NetBox prefixes
Warnings:
⚠ Prefix 10.0.5.0/24 exists in NetBox but not in Subnetter config
⚠ Tenant "legacy-account" exists in NetBox but not in Subnetter config
Summary: 0 conflicts, 2 warnings

subnetter netbox import

Generate Subnetter config from existing NetBox prefixes.

Terminal window
subnetter netbox import \
--netbox-url https://netbox.example.com \
--netbox-token $NETBOX_TOKEN \
--output config.json \
[--tenant <name>] # Filter by tenant
[--site <name>] # Filter by site
[--tag <name>] # Filter by tag

Configuration

Environment Variables

Terminal window
# NetBox connection
NETBOX_URL=https://netbox.example.com
NETBOX_TOKEN=your-api-token
# Optional defaults
NETBOX_DEFAULT_TENANT=default
NETBOX_SSL_VERIFY=true

Config File Extension (Optional)

{
"baseCidr": "10.0.0.0/8",
"netbox": {
"url": "https://netbox.example.com",
"defaultTenant": "my-org",
"createMissing": true,
"tags": ["subnetter-managed", "production"]
},
"accounts": [...]
}

Error Handling

Conflict Types

ConflictSeverityBehavior
Overlapping prefix (different tenant)ErrorBlock export
Overlapping prefix (same tenant)WarningAllow with flag
Missing tenantErrorBlock unless --create-missing
Missing siteErrorBlock unless --create-missing
Missing roleWarningCreate automatically
API rate limitRetryExponential backoff
Auth failureErrorImmediate fail with clear message

Error Messages

Error: Prefix conflict detected
Subnetter allocation: 10.0.1.0/24 (ecommerce-production, us-east-1, Public)
NetBox prefix: 10.0.1.0/24 (legacy-tenant, us-east-1, Unknown)
These prefixes overlap but belong to different tenants.
Options:
1. Update the NetBox prefix to match Subnetter's tenant
2. Modify your Subnetter config to avoid this range
3. Use --force to overwrite (dangerous)

Testing Strategy

Unit Tests

  • Mapper functions (Subnetter ↔ NetBox)
  • Diff calculation
  • Conflict detection

Integration Tests

  • NetBox API client against mock server
  • Full export/import cycle

E2E Tests (requires running NetBox)

  • Export allocations to real NetBox
  • Validate against real NetBox
  • Import from real NetBox
  • Round-trip: export → import → compare

Test Fixtures

packages/netbox/tests/fixtures/
├── subnetter-configs/
│ ├── simple.json
│ ├── multi-account.json
│ └── multi-cloud.json
├── netbox-responses/
│ ├── prefixes.json
│ ├── tenants.json
│ └── sites.json
└── expected-outputs/
├── export-diff.json
└── import-config.json

Implementation Phases

Phase 1: Export (MVP) In Progress

  • Create @subnetter/netbox package
  • Implement NetBox API client
  • Implement basic export (prefixes only)
  • Add netbox export CLI command
  • Add --dry-run support
  • Basic documentation

Phase 2: Validation & Robustness

  • Implement conflict detection
  • Add netbox validate CLI command
  • Create missing tenants/sites/roles
  • Improve error messages
  • Add retry logic for API calls

Phase 3: Import

  • Implement NetBox → Subnetter mapping
  • Add netbox import CLI command
  • Handle partial imports (filters)
  • Round-trip testing

Phase 4: Advanced Features

  • Custom field support
  • VLAN integration
  • Webhook support for sync
  • Nautobot compatibility

Open Questions

  1. AZ Representation: Should AZs be Sites, Locations, or Tags in NetBox?

    • Sites: More structured, but creates many objects
    • Tags: Simpler, but less queryable
    • Recommendation: Tags with format az:<az-name>
  2. VPC Representation: How to represent VPCs in NetBox?

    • Separate Prefix with role “VPC”
    • Custom field on child prefixes
    • Recommendation: Prefix with role “VPC” as container
  3. Deletion Policy: What happens to NetBox prefixes removed from Subnetter?

    • Delete automatically
    • Mark as deprecated
    • Require explicit flag
    • Recommendation: Require --prune flag to delete
  4. Multi-tenancy: One Subnetter config per NetBox tenant, or one config for all?

    • Recommendation: Support both via --tenant filter

Dependencies

{
"dependencies": {
"axios": "^1.6.0",
"zod": "^3.22.0"
},
"devDependencies": {
"nock": "^13.4.0",
"@types/node": "^20.0.0"
}
}

References