k8s-netbox-controller

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 26, 2026 License: Apache-2.0

README ΒΆ

k8s-netbox-controller

GitHub Release Go Report Card License

A Kubernetes controller that automatically assigns IP addresses from NetBox to LoadBalancer type Services.

Overview

k8s-netbox-controller watches for Kubernetes Service resources of type LoadBalancer and automatically allocates IP addresses from NetBox IP Address Management (IPAM) system. When a Service is created with the appropriate annotations, the controller:

  1. πŸ” Queries NetBox for the next available IP from a specified subnet
  2. πŸ“ Assigns the IP to the Service's spec.loadBalancerIP field
  3. 🧹 Automatically releases the IP from NetBox when the Service is deleted

This enables seamless integration between Kubernetes and NetBox for IP address lifecycle management, particularly useful in on-premises or bare-metal Kubernetes deployments.

Features

  • βœ… Automatic IP allocation from NetBox prefixes (subnets)
  • βœ… VRF support for multi-tenant environments
  • βœ… Automatic cleanup using Kubernetes finalizers
  • βœ… Opt-in behavior via annotations (doesn't affect all Services)
  • βœ… Idempotent reconciliation (safe to run multiple times)
  • βœ… Comprehensive logging with structured logs
  • βœ… Metrics endpoint for monitoring

Prerequisites

  • Kubernetes: v1.32.x - v1.35.x+ (compatibility matrix)
  • NetBox: v3.5+ or v4.0+ with API access
  • kubectl: v1.32+
  • Go: v1.25+ (for building from source)
  • Docker/Podman: For building container images

Quick Start

1. Deploy the Controller
# Install the chart from GitHub Container Registry
helm install k8s-netbox-controller \
  oci://ghcr.io/ascalotoru/charts/k8s-netbox-controller \
  --version 0.1.0 \
  --namespace k8s-netbox-controller-system \
  --create-namespace \
  --set netbox.url=https://netbox.example.com \
  --set netbox.token=your-netbox-api-token
Option B: Using kubectl with pre-built manifest
kubectl apply -f https://raw.githubusercontent.com/ascalotoru/k8s-netbox-controller/main/dist/install.yaml

Then configure NetBox credentials:

kubectl create secret generic netbox-credentials \
  --namespace k8s-netbox-controller-system \
  --from-literal=NETBOX_URL=https://netbox.example.com \
  --from-literal=NETBOX_TOKEN=your-netbox-api-token

kubectl patch deployment k8s-netbox-controller-controller-manager \
  -n k8s-netbox-controller-system \
  --type='json' \
  -p='[{"op": "add", "path": "/spec/template/spec/containers/0/envFrom", "value": [{"secretRef": {"name": "netbox-credentials"}}]}]'
Option C: Using Kustomize
# Clone the repository
git clone https://github.com/ascalotoru/k8s-netbox-controller.git
cd k8s-netbox-controller

# Build and deploy
export IMG=ghcr.io/ascalotoru/k8s-netbox-controller:latest
make deploy IMG=$IMG
2. Verify Installation
2. Verify Installation

Check that the controller is running:

kubectl get pods -n k8s-netbox-controller-system
3. Create a LoadBalancer Service

Apply a Service with NetBox annotations:

apiVersion: v1
kind: Service
metadata:
  name: my-application
  annotations:
    netbox-controller.ascalotoru.io/netbox-sync: "true"
    netbox-controller.ascalotoru.io/subnet: "192.168.1.0/24"
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

The controller will automatically assign an IP from NetBox:

kubectl get svc my-application
# NAME             TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)
# my-application   LoadBalancer   10.96.123.45    192.168.1.100   80:31234/TCP

Configuration

Annotations
Annotation Required Description Example
netbox-controller.ascalotoru.io/netbox-sync Yes Enable NetBox IP allocation "true"
netbox-controller.ascalotoru.io/subnet Yes NetBox prefix (CIDR) to allocate from "192.168.1.0/24"
netbox-controller.ascalotoru.io/vrf-name No VRF name (if using VRFs) "production"
Environment Variables

The controller requires these environment variables (typically set via Secret):

Variable Required Description
NETBOX_URL Yes NetBox API base URL
NETBOX_TOKEN Yes NetBox API authentication token
Helm Chart Values

Key Helm values you can configure:

Parameter Description Default
netbox.url NetBox API URL ""
netbox.token NetBox API token ""
netbox.existingSecret Use existing secret for credentials ""
replicaCount Number of controller replicas 1
image.repository Controller image repository ghcr.io/ascalotoru/k8s-netbox-controller
image.tag Controller image tag Chart's appVersion
resources.limits.memory Memory limit 128Mi
resources.requests.cpu CPU request 10m
leaderElection.enabled Enable leader election (for HA) false

See charts/k8s-netbox-controller/values.yaml for all available options.

Examples

See the examples/ directory for complete examples:

With VRF Support
apiVersion: v1
kind: Service
metadata:
  name: production-service
  annotations:
    netbox-controller.ascalotoru.io/netbox-sync: "true"
    netbox-controller.ascalotoru.io/subnet: "10.100.0.0/24"
    netbox-controller.ascalotoru.io/vrf-name: "production"
spec:
  type: LoadBalancer
  selector:
    app: prod-app
  ports:
    - port: 443
      targetPort: 8443

Kubernetes Compatibility

This controller uses Kubernetes client libraries v0.34.x and is compatible with:

Kubernetes Version Support Status
1.32.x βœ… Compatible
1.33.x βœ… Officially Supported
1.34.x βœ… Tested
1.35.x+ βœ… Expected to work

Following Kubernetes version skew policy, the controller maintains compatibility with Β±1 minor version from the client library version.

Development

Local Development
# Clone the repository
git clone https://github.com/ascalotoru/k8s-netbox-controller.git
cd k8s-netbox-controller

# Install dependencies
go mod download

# Run tests
make test

# Run locally (requires kubeconfig)
export NETBOX_URL=http://localhost:8000
export NETBOX_TOKEN=your-dev-token
make run
Building
# Build the binary
make build

# Build Docker image
make docker-build IMG=your-registry/k8s-netbox-controller:dev

# Run linting
make lint
Testing
# Unit tests
make test

# E2E tests (requires Kind)
make test-e2e

# Check coverage
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Kubernetes Cluster                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚   Service    β”‚ watches β”‚  k8s-netbox-controller   β”‚     β”‚
β”‚  β”‚ (LoadBalancer)│────────▢│  - ServiceReconciler    β”‚     β”‚
β”‚  β”‚              β”‚         β”‚  - NetBox Client         β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                                      β”‚ API Calls            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚
                                       β–Ό
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚     NetBox      β”‚
                              β”‚   IPAM System   β”‚
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

How it works:

  1. Controller watches for Service resources with annotation netbox-sync: "true"
  2. When a LoadBalancer Service is created without an IP:
    • Queries NetBox API for next available IP in specified subnet
    • Updates Service spec.loadBalancerIP with allocated IP
    • Adds finalizer for cleanup tracking
  3. When Service is deleted:
    • Finalizer triggers cleanup
    • Releases IP back to NetBox
    • Removes finalizer

Troubleshooting

Controller logs
kubectl logs -n k8s-netbox-controller-system \\
  deployment/k8s-netbox-controller-controller-manager \\
  -c manager -f
Common Issues

Service IP not assigned:

  • Check controller logs for errors
  • Verify NetBox URL and token are correct
  • Ensure the subnet exists in NetBox
  • Verify subnet has available IPs

IP not released on deletion:

  • Check if finalizer is present: kubectl get svc <name> -o yaml | grep finalizers
  • Review controller logs during Service deletion

Permission errors:

  • Ensure RBAC manifests are applied: make install
  • Verify ServiceAccount has proper permissions

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request
Code Guidelines
  • Follow Go best practices and formatting (make fmt)
  • Add tests for new features
  • Update documentation as needed
  • Run linter before submitting (make lint-fix)

Roadmap

  • Support for IP allocation on Service update
  • Configurable IP description templates
  • Webhook for validation
  • Helm chart distribution
  • Metrics dashboard examples
  • Multi-IP support for Services

Acknowledgments

Built with Kubebuilder and inspired by the need for better IP address management in bare-metal Kubernetes environments.

Support

  • NetBox - IP address management (IPAM) and data center infrastructure management (DCIM) tool
  • MetalLB - Load balancer implementation for bare metal Kubernetes
  • Kubebuilder - SDK for building Kubernetes APIs

NOTE: Run make help for more information on all available make targets.

More information can be found via the Kubebuilder Documentation

License

Copyright 2026.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Directories ΒΆ

Path Synopsis
internal
pkg
test

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL