Kubernetes operator for managing DNS zones and records, with a pluggable backend architecture. This repository provides:
- Custom resources to model zones, recordsets, and zone classes
- Controllers for two runtime roles:
- "downstream" agent that programs a DNS backend (PowerDNS supported)
- "replicator" that mirrors resources from an upstream cluster to a downstream cluster and synthesizes status
- Kustomize overlays to deploy either role
-
DNSZoneClass(cluster-scoped)spec.controllerName: selects backend controller (e.g., "powerdns")spec.nameServerPolicy: currently supportsStaticwithservers: []spec.defaults.defaultTTL: optional default TTL for zones
-
DNSZone(namespaced)spec.domainName: required zone FQDN (e.g.,example.com)spec.dnsZoneClassName: optional reference to aDNSZoneClassstatus.nameservers: authoritative nameservers (derived from class policy)status.conditions:Accepted,Programmed
-
DNSRecordSet(namespaced)spec.dnsZoneRef:LocalObjectReferenceto aDNSZonein the same namespacespec.recordType: one ofA, AAAA, CNAME, TXT, MX, SRV, CAA, NS, SOA, PTR, TLSA, HTTPS, SVCBspec.records[]: owners with typed fields per record type (orrawstrings). TTL per-owner optional.status.conditions:Accepted,Programmed
-
Downstream role (
--role=downstream)DNSZoneReconciler: whenDNSZone.spec.dnsZoneClassNamereferences a class withcontrollerName: powerdns, ensures the zone exists in PowerDNS and honors static nameserver policy.DNSRecordSetReconciler: for PowerDNS-backed zones, applies recordsets to PDNS using an authoritative mode that REPLACEs desired owners and DELETEs extraneous owners of the same type. Requeues while the zone is not ready.
-
Replicator role (
--role=replicator)- Multicluster manager discovers one or many upstream clusters (single-cluster or Milo discovery) and mirrors
DNSZone/DNSRecordSetinto a configured downstream cluster using a mapped-namespace strategy. DNSZoneReplicator:- Mirrors upstream
specinto a downstream shadow object - Ensures an operator-managed upstream
DNSRecordSetnamedsoaexists (typed SOA targeting@) for PowerDNS-backed zones - Updates upstream
status: setsAccepted=Trueand currently treatsProgrammed=Trueoptimistically; fillsstatus.nameserversfromDNSZoneClasswhenStaticpolicy is set
- Mirrors upstream
DNSRecordSetReplicator:- Mirrors upstream
specinto a downstream shadow object - Updates upstream
status:AcceptedreflectsDNSZonepresence;Programmed=Trueonce downstream shadow ensured
- Mirrors upstream
- Multicluster manager discovers one or many upstream clusters (single-cluster or Milo discovery) and mirrors
- PowerDNS (Authoritative)
- Enabled when
DNSZoneClass.spec.controllerName: powerdns - The downstream agent uses environment variables to connect:
PDNS_API_URL(defaulthttp://127.0.0.1:8081)PDNS_API_KEYorPDNS_API_KEY_FILE
- Recordset translation supports typed fields for all declared RR types and sensible normalization of names and quoting for TXT/targets.
- Enabled when
-
config/agent/- Namespace:
dns-agent-system - Runs the operator with
--role=downstream - Merges a
pdnssidecar container into the controller Deployment to run PowerDNS alongside the manager - Mounts a shared
emptyDirto exchange an auto-generated API key, and setsPDNS_API_KEY_FILEin the manager - Provides a
Serviceexposing PDNS ports 53/udp, 53/tcp, and 8081/tcp - ConfigMap
server-configwired to--server-config
- Namespace:
-
config/overlays/replicator/- Namespace:
dns-replicator-system - Runs the operator with
--role=replicator - Requires a Secret
downstream-kubeconfigcontaining keykubeconfigto target the downstream cluster - ConfigMap
server-configsets discovery mode (defaults tosingle) and pointsdownstreamResourceManagement.kubeconfigPathto/downstream/kubeconfig
- Namespace:
- Install CRDs and default manifests:
kubectl apply -k config/agent
- Create a
DNSZoneClassfor PowerDNS with static nameservers, for example:
apiVersion: dns.networking.miloapis.com/v1alpha1
kind: DNSZoneClass
metadata:
name: powerdns
spec:
controllerName: powerdns
nameServerPolicy:
mode: Static
static:
servers: ["ns1.example.net.", "ns2.example.net."]- Create a
DNSZoneand aDNSRecordSet:
apiVersion: dns.networking.miloapis.com/v1alpha1
kind: DNSZone
metadata:
name: example-com
namespace: default
spec:
domainName: example.com
dnsZoneClassName: powerdns
---
apiVersion: dns.networking.miloapis.com/v1alpha1
kind: DNSRecordSet
metadata:
name: www-a
namespace: default
spec:
dnsZoneRef:
name: example-com
recordType: A
records:
- name: www
a:
content: ["192.0.2.10", "192.0.2.11"]
ttl: 300- Create Secret on the replicator namespace containing the downstream kubeconfig (
data.kubeconfig):
kubectl -n dns-replicator-system create secret generic downstream-kubeconfig \
--from-file=kubeconfig=/path/to/downstream/kubeconfig- Deploy replicator overlay:
kubectl apply -k config/overlays/replicator- Create
DNSZoneClass(cluster-scoped),DNSZoneandDNSRecordSeton the upstream cluster. The replicator will mirror them into the downstream cluster and update upstreamstatusconditions.
Accepted: resource is valid and has required dependencies (e.g.,DNSRecordSetsees itsDNSZone)Programmed: desired state is realized (shadow exists downstream; for downstream agent, recordsets applied to backend)
kind: DNSOperator(internal config consumed by the binary via--server-config)discovery.mode:singleormilodownstreamResourceManagement.kubeconfigPath: path inside the Pod to the downstream kubeconfig
- Build:
make docker-build(seeMakefile) - Generate code/manifests:
make generateandmake manifests - Local e2e: see
test/e2e/chainsaw-test.yamland sample manifests underconfig/samples/