provider-clusterbook is a Crossplane Provider that
manages IP address reservations from a clusterbook
REST API. It reserves IPs from network pools, optionally creates PowerDNS
wildcard DNS records, and exposes the assigned addresses in status.
- IP reservation — reserve one or more IPs from a clusterbook network pool
- Explicit or auto-assign — optionally specify an exact IP, or let clusterbook auto-assign from the pool
- PowerDNS integration — optionally create wildcard DNS records for reserved IPs via
createDNS - Drift detection — observes the clusterbook API and reconciles on changes
- TLS support — custom CA certificates and insecure skip-verify for self-signed endpoints
| Kind | Scope | Description |
|---|---|---|
ProviderConfig |
Namespaced | Clusterbook API connection settings (namespaced) |
ClusterProviderConfig |
Cluster | Clusterbook API connection settings (cluster-scoped) |
IPReservation |
Cluster | Managed resource — reserves IPs from a network pool |
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-clusterbook
spec:
package: ghcr.io/stuttgart-things/provider-clusterbook-xpkg:v3.1apiVersion: clusterbook.stuttgart-things.com/v1alpha1
kind: ClusterProviderConfig
metadata:
name: default
spec:
url: "http://clusterbook.clusterbook.svc.cluster.local:8080"For TLS endpoints with a custom CA:
apiVersion: clusterbook.stuttgart-things.com/v1alpha1
kind: ClusterProviderConfig
metadata:
name: default
spec:
url: "https://clusterbook.example.com"
customCA: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----For self-signed certificates (development only):
apiVersion: clusterbook.stuttgart-things.com/v1alpha1
kind: ClusterProviderConfig
metadata:
name: default
spec:
url: "https://clusterbook.example.com"
insecureSkipTLSVerify: trueAuto-assign an IP from a network pool:
apiVersion: ipreservation.clusterbook.stuttgart-things.com/v1alpha1
kind: IPReservation
metadata:
name: my-cluster-ip
spec:
forProvider:
networkKey: "10.31.103"
clusterName: my-cluster
count: 1
providerConfigRef:
name: default
kind: ClusterProviderConfigReserve a specific IP with DNS record:
apiVersion: ipreservation.clusterbook.stuttgart-things.com/v1alpha1
kind: IPReservation
metadata:
name: my-cluster-ip
spec:
forProvider:
networkKey: "10.31.103"
clusterName: my-cluster
ip: "10.31.103.42"
createDNS: true
providerConfigRef:
name: default
kind: ClusterProviderConfig$ kubectl get ipreservation
NAME READY SYNCED NETWORK CLUSTER AGE
my-cluster-ip True True 10.31.103 my-cluster 5m
$ kubectl get ipreservation my-cluster-ip -o jsonpath='{.status.atProvider}' | jq
{
"ipAddresses": ["10.31.103.42"],
"status": "ASSIGNED:DNS"
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
networkKey |
string | Yes | — | Network pool key (e.g. 10.31.103) |
clusterName |
string | Yes | — | Cluster name to assign IPs to |
count |
integer | No | 1 | Number of IPs to reserve |
ip |
string | No | — | Explicit IP (skips auto-assignment) |
createDNS |
boolean | No | false | Create a PDNS wildcard DNS record |
| Field | Type | Description |
|---|---|---|
ipAddresses |
[]string | List of assigned IP addresses |
status |
string | Assignment status (ASSIGNED or ASSIGNED:DNS) |
- Go 1.23+
- Docker
- Make
# Initialize the build submodule (first time only)
make submodules
# Generate CRDs, deepcopy, and run linters
make reviewable
# Build the provider binary and Docker image
make buildgo test ./internal/... -v -count=1apis/
v1alpha1/ # ProviderConfig, ClusterProviderConfig types
ipreservation/
v1alpha1/ # IPReservation managed resource type
internal/
client/ # Clusterbook REST API client
controller/
config/ # ProviderConfig controller
ipreservation/ # IPReservation reconciler
clusterbook.go # Controller registration
package/
crds/ # Generated CRDs
crossplane.yaml # Crossplane package metadata
| Flag | Default | Description |
|---|---|---|
--debug / -d |
false |
Enable debug logging |
--leader-election / -l |
false |
Enable leader election for HA |
--poll |
1m |
How often to check each resource for drift |
--sync / -s |
1h |
Controller manager sync period |
--max-reconcile-rate |
10 |
Max reconciliations per second |