bind-operator

A Kubernetes operator that manages fleets of BIND9 servers declaratively: StatefulSet-backed clusters with primary/secondary replication, and zones, views, TSIG keys, ACLs, catalog zones, RPZ policies and DNSSEC policies as custom resources.

Architecture

Each BindCluster is a StatefulSet plus a headless Service (stable per-pod DNS) and a client Service. Ordinal-0 is the primary; the remaining pods are secondaries that replicate via AXFR/IXFR + NOTIFY. A per-pod PVC holds zone databases and journals.

Zone content is delivered dynamically: the operator execs rndc addzone and TSIG nsupdate against the primary pod (the same write path external-dns uses). Cluster-wide config — options, controls, ACLs, views, dnssec-policy blocks and response-policy clauses — is rendered into a ConfigMap-backed named.conf and reloaded with rndc reconfig. New zones land on the secondaries automatically through a catalog zone, so secondaries never need per-zone reconfiguration.

BindCluster ──> StatefulSet (pod-0 = primary, pod-N = secondaries)
                 ├─ headless Service   (pod-0.<cluster>-headless.<ns>.svc…)
                 ├─ client Service     (ClusterIP / LoadBalancer)
                 ├─ ConfigMap          (named.conf.primary / .secondary + entrypoint)
                 ├─ Secret <cluster>-keys   (TSIG key clauses, included by named.conf)
                 └─ Secret <cluster>-rndc   (rndc control key)

BindZone / DNSRecord ──rndc addzone + nsupdate──> primary ──catalog + AXFR──> secondaries

The named.conf is rendered in two variants (primary/secondary); an entrypoint script picks one based on the pod ordinal.

Custom Resources

Kind Purpose
BindCluster A set of BIND9 servers. spec.mode: authoritative or resolver.
BindZone A forward/reverse zone (primary/secondary/forward/stub), records inline, optional dynamic-update + DNSSEC + catalog membership.
DNSRecord A single record set applied via TSIG nsupdate — external-dns as a CRD.
BindView A split-horizon view (match-clients, ordering, per-view recursion).
BindTSIGKey A TSIG key; the operator generates material into a Secret (never stored in the CR). spec.secretTemplate stamps extra labels/annotations onto that Secret (e.g. reflection hints to mirror it into another namespace).
BindACL A reusable named address_match_list.
BindCatalogZone A BIND catalog zone so secondaries auto-provision member zones.
BindPolicy A Response Policy Zone (RPZ) / DNS firewall.
BindDNSSECPolicy A dnssec-policy for automated signing.

See config/samples/ for worked examples.

Migration mapping

The three Puppet-managed BIND roles map onto three BindClusters:

Puppet role BindCluster Mode
3× authoritative masters auth authoritative (pod-0 primary, 2 secondaries)
3× only-resolvers resolver resolver (3 identical recursive servers)
3× external-dns externaldns authoritative (zones set dynamicUpdate for RFC2136 TSIG updates)

Development

make generate   # regenerate deepcopy, CRDs and RBAC from kubebuilder markers
make build      # build the operator binary
make test       # go test -race
make lint fmt   # go vet / gofmt

Local (kind)

kind create cluster --name bind
docker build -t bind-operator:dev -f Dockerfile.operator .
kind load docker-image bind-operator:dev --name bind

kubectl apply -f config/crd/bases/
kubectl apply -f hack/kind/manifests/
kubectl apply -f config/samples/

CI

Woodpecker runs pre-commit (gofmt + vet), test, and a dry-run image build on pull requests; pushing a v* tag builds and pushes artifactapi.k8s.syd1.au.unkin.net/docker-internal/bind-operator (and bind-tsig-api) to the artifactapi local docker registry.

Notes & caveats

  • The BIND container image (spec.image, default internetsystemsconsortium/bind9:9.20) must ship named, rndc and nsupdate. The operator projects its config at /etc/bind-operator (leaving the image's own /etc/bind, including bind.keys, intact) and runs named -g -c /run/named/named.conf.
  • Dynamic updates authenticate with nsupdate -y; the TSIG secret is passed on the argv of an exec'd process inside the pod.
  • RPZ IP-trigger encodings (ip, client-ip, nsip) are emitted verbatim; QNAME and NSDNAME triggers are fully supported.
S
Description
Kubernetes operator for managing BIND9 DNS clusters, zones, views, and TSIG keys
Readme 527 KiB
Languages
Go 99.1%
Makefile 0.9%