Initial bind-operator: 9 CRDs + controllers
Implements a Kubernetes operator that manages fleets of BIND9 servers declaratively, using controller-runtime (matching forgebot conventions). - add BindCluster reconciler: StatefulSet (pod-0 primary, secondaries), headless + client Services, rendered named.conf ConfigMap, TSIG keys Secret and rndc control Secret; watches dependent CRs to re-render - add BindTSIGKey reconciler that generates key material into a Secret - add BindZone/DNSRecord reconcilers using fully-dynamic delivery (rndc addzone + TSIG nsupdate against the primary pod) - add BindCatalogZone reconciler so secondaries auto-provision zones - add BindPolicy (RPZ), BindDNSSECPolicy, BindView, BindACL reconcilers - render primary/secondary named.conf variants selected by pod ordinal - generate CRDs, deepcopy and RBAC; add samples mapping the three Puppet roles (authoritative/resolver/external-dns) to three BindClusters - add Makefile, Dockerfile.operator, Woodpecker CI and kind manifests
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
---
|
||||
# TSIG key used to authenticate zone transfers between primary and secondaries
|
||||
# (and catalog zone transfers). The operator generates the material into a
|
||||
# Secret named <name>-tsig; the key never appears in the CR.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindTSIGKey
|
||||
metadata:
|
||||
name: transfer-key
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
algorithm: hmac-sha256
|
||||
---
|
||||
# TSIG key permitting external-dns (and DNSRecord objects) to send RFC2136
|
||||
# dynamic updates to the dynamic cluster's primary.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindTSIGKey
|
||||
metadata:
|
||||
name: externaldns-key
|
||||
namespace: bind-externaldns
|
||||
spec:
|
||||
algorithm: hmac-sha256
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
# Authoritative masters role (replaces 3x Puppet authoritative servers).
|
||||
# Ordinal-0 is the primary holding zone data; the other two replicate via the
|
||||
# catalog zone + AXFR/IXFR.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindCluster
|
||||
metadata:
|
||||
name: auth
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
mode: authoritative
|
||||
replicas: 3
|
||||
storageSize: 2Gi
|
||||
service:
|
||||
type: LoadBalancer
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
---
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindACL
|
||||
metadata:
|
||||
name: internal-nets
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
clusterRef: auth
|
||||
entries:
|
||||
- 10.0.0.0/8
|
||||
- 192.168.0.0/16
|
||||
---
|
||||
# Catalog zone: new BindZones are auto-provisioned onto the secondaries.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindCatalogZone
|
||||
metadata:
|
||||
name: auth-catalog
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
clusterRef: auth
|
||||
zoneName: catalog.internal
|
||||
transferKeyRef: transfer-key
|
||||
---
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindDNSSECPolicy
|
||||
metadata:
|
||||
name: standard
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
clusterRef: auth
|
||||
algorithm: ecdsap256sha256
|
||||
nsec3: true
|
||||
csk:
|
||||
lifetime: unlimited
|
||||
---
|
||||
# Forward zone (signed) with a couple of seeded records.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindZone
|
||||
metadata:
|
||||
name: example-internal
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
clusterRef: auth
|
||||
zoneName: internal.example.com
|
||||
type: primary
|
||||
defaultTTL: 3600
|
||||
dnssecPolicyRef: standard
|
||||
allowTransfer:
|
||||
- key transfer-key
|
||||
updateKeyRef: transfer-key
|
||||
dynamicUpdate: true
|
||||
records:
|
||||
- name: "@"
|
||||
type: NS
|
||||
values: ["ns1.internal.example.com."]
|
||||
- name: ns1
|
||||
type: A
|
||||
values: ["10.0.0.53"]
|
||||
- name: www
|
||||
type: A
|
||||
values: ["10.0.1.10", "10.0.1.11"]
|
||||
---
|
||||
# Reverse zone for 10.0.0.0/16.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindZone
|
||||
metadata:
|
||||
name: reverse-10-0
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
clusterRef: auth
|
||||
zoneName: 0.10.in-addr.arpa
|
||||
type: primary
|
||||
updateKeyRef: transfer-key
|
||||
dynamicUpdate: true
|
||||
allowTransfer:
|
||||
- key transfer-key
|
||||
records:
|
||||
- name: "53.0"
|
||||
type: PTR
|
||||
values: ["ns1.internal.example.com."]
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
# Recursive resolvers role (replaces 3x Puppet only-resolver servers).
|
||||
# All three pods are identical recursive servers; no zone replication.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindCluster
|
||||
metadata:
|
||||
name: resolver
|
||||
namespace: bind-resolver
|
||||
spec:
|
||||
mode: resolver
|
||||
replicas: 3
|
||||
service:
|
||||
type: LoadBalancer
|
||||
forwarders:
|
||||
- 1.1.1.1
|
||||
- 9.9.9.9
|
||||
---
|
||||
# Conditional forwarding of an internal zone to the authoritative cluster.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindZone
|
||||
metadata:
|
||||
name: forward-internal
|
||||
namespace: bind-resolver
|
||||
spec:
|
||||
clusterRef: resolver
|
||||
zoneName: internal.example.com
|
||||
type: forward
|
||||
catalog: false
|
||||
forwarders:
|
||||
- 10.0.0.53
|
||||
---
|
||||
# DNS firewall (RPZ) blocklist applied to the resolvers.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindPolicy
|
||||
metadata:
|
||||
name: blocklist
|
||||
namespace: bind-resolver
|
||||
spec:
|
||||
clusterRef: resolver
|
||||
zoneName: rpz.internal
|
||||
order: 10
|
||||
transferKeyRef: transfer-key
|
||||
rules:
|
||||
- trigger: qname
|
||||
match: malware.example.
|
||||
action: nxdomain
|
||||
- trigger: qname
|
||||
match: tracker.example.
|
||||
action: cname
|
||||
target: blocked.internal.example.com
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
# external-dns role (replaces 3x Puppet external-dns servers). The primary
|
||||
# accepts RFC2136 TSIG updates from external-dns; secondaries replicate.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindCluster
|
||||
metadata:
|
||||
name: externaldns
|
||||
namespace: bind-externaldns
|
||||
spec:
|
||||
mode: dynamic
|
||||
replicas: 3
|
||||
service:
|
||||
type: LoadBalancer
|
||||
---
|
||||
# Public zone that external-dns writes into via nsupdate/TSIG.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindZone
|
||||
metadata:
|
||||
name: example-com
|
||||
namespace: bind-externaldns
|
||||
spec:
|
||||
clusterRef: externaldns
|
||||
zoneName: example.com
|
||||
type: primary
|
||||
dynamicUpdate: true
|
||||
updateKeyRef: externaldns-key
|
||||
allowTransfer:
|
||||
- key externaldns-key
|
||||
---
|
||||
# A record managed as a CRD (external-dns-style) instead of via the RFC2136
|
||||
# controller — same write path (TSIG nsupdate to the primary).
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: DNSRecord
|
||||
metadata:
|
||||
name: www-example-com
|
||||
namespace: bind-externaldns
|
||||
spec:
|
||||
zoneRef: example-com
|
||||
name: www
|
||||
type: A
|
||||
ttl: 300
|
||||
values:
|
||||
- 203.0.113.10
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
# Split-horizon example: an internal view answering RFC1918 clients and a
|
||||
# default external view. Bind a zone to a view via BindZone.spec.viewRef.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindView
|
||||
metadata:
|
||||
name: internal
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
clusterRef: auth
|
||||
order: 10
|
||||
matchClients:
|
||||
- internal-nets
|
||||
recursion: false
|
||||
---
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindView
|
||||
metadata:
|
||||
name: external
|
||||
namespace: bind-auth
|
||||
spec:
|
||||
clusterRef: auth
|
||||
order: 100
|
||||
matchClients:
|
||||
- any
|
||||
recursion: false
|
||||
Reference in New Issue
Block a user