Skip to content

Bind9Instance Specification

Complete specification for the Bind9Instance Custom Resource Definition.

Resource Definition

apiVersion: bindy.firestoned.io/v1beta1
kind: Bind9Instance
metadata:
  name: string
  namespace: string
  labels:
    key: value
spec:
  clusterRef: string          # References Bind9Cluster
  role: primary|secondary     # Required: Server role
  replicas: integer
  version: string             # Optional, overrides cluster version
  image:                      # Optional, overrides cluster image
    image: string
    imagePullPolicy: string
    imagePullSecrets: [string]
  configMapRefs:              # Optional, custom config files
    namedConf: string
    namedConfOptions: string
  global:                     # Optional, overrides cluster global config
    recursion: boolean
    allowQuery: [string]
    allowTransfer: [string]
    dnssec:
      enabled: boolean
      validation: boolean
    forwarders: [string]
    listenOn: [string]
    listenOnV6: [string]
    rateLimit:                # Optional, Response Rate Limiting (on by default)
      responsesPerSecond: integer
  primaryServers: [string]    # Required for secondary role

Spec Fields

clusterRef

Type: string Required: Yes

Name of the Bind9Cluster that this instance belongs to. The instance inherits cluster-level configuration (version, shared config, TSIG keys, ACLs) from the referenced cluster.

spec:
  clusterRef: production-dns  # References Bind9Cluster named "production-dns"

How It Works: - Instance inherits version from cluster unless overridden - Instance inherits global config from cluster unless overridden - Operator uses cluster TSIG keys for zone transfers - Instance can override cluster settings with its own spec

replicas

Type: integer Required: No Default: 1

Number of BIND9 pod replicas to run.

spec:
  replicas: 3

Best Practices: - Use 2+ replicas for high availability - Use odd numbers (3, 5) for consensus-based systems - Consider resource constraints when scaling

version

Type: string Required: No Default: "9.18"

BIND9 version to deploy. Must match available Docker image tags.

spec:
  version: "9.18"

Supported Versions: - "9.16" - Older stable - "9.18" - Current stable (recommended) - "9.19" - Development

image

Type: object Required: No

Container image configuration for the BIND9 instance. Overrides cluster-level image configuration.

spec:
  image:
    image: "my-registry.example.com/bind9:custom"
    imagePullPolicy: "Always"
    imagePullSecrets:
      - my-registry-secret

How It Works: - If not specified, inherits from Bind9Cluster.spec.image - If cluster doesn't specify, uses default image internetsystemsconsortium/bind9:9.18 - Instance-level configuration takes precedence over cluster configuration

image.image

Type: string Required: No Default: "internetsystemsconsortium/bind9:9.18"

Full container image reference including registry, repository, and tag.

spec:
  image:
    image: "docker.io/internetsystemsconsortium/bind9:9.18"

Examples: - Public registry: "internetsystemsconsortium/bind9:9.18" - Private registry: "my-registry.example.com/dns/bind9:custom" - With digest: "bind9@sha256:abc123..."

image.imagePullPolicy

Type: string Required: No Default: "IfNotPresent"

Kubernetes image pull policy.

spec:
  image:
    imagePullPolicy: "Always"

Valid Values: - "Always" - Always pull the image - "IfNotPresent" - Pull only if not present locally (recommended) - "Never" - Never pull, use local image only

image.imagePullSecrets

Type: array of strings Required: No Default: []

List of Kubernetes secret names for authenticating with private container registries.

spec:
  image:
    imagePullSecrets:
      - docker-registry-secret
      - gcr-pull-secret

Setup: 1. Create a docker-registry secret:

kubectl create secret docker-registry my-registry-secret \
  --docker-server=my-registry.example.com \
  --docker-username=user \
  --docker-password=pass \
  --docker-email=email@example.com
2. Reference the secret name in imagePullSecrets

configMapRefs

Type: object Required: No

References to custom ConfigMaps containing BIND9 configuration files. Overrides cluster-level ConfigMap references.

spec:
  configMapRefs:
    namedConf: "my-custom-named-conf"
    namedConfOptions: "my-custom-options"

How It Works: - If specified, Bindy uses your custom ConfigMaps instead of auto-generating configuration - If not specified, Bindy auto-generates ConfigMaps from the config block - Instance-level references override cluster-level references - You can specify one or both ConfigMaps

Default Behavior: - If configMapRefs is not set, Bindy creates a ConfigMap named <instance-name>-config - Auto-generated ConfigMap includes both named.conf and named.conf.options - Configuration is built from the config block in the spec

configMapRefs.namedConf

Type: string Required: No

Name of ConfigMap containing the main named.conf file.

spec:
  configMapRefs:
    namedConf: "my-named-conf"

ConfigMap Format:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-named-conf
  namespace: bindy-system
data:
  named.conf: |
    // Custom BIND9 configuration
    include "/etc/bind/named.conf.options";
    include "/etc/bind/zones/named.conf.zones";

    logging {
      channel custom_log {
        file "/var/log/named/queries.log" versions 3 size 5m;
        severity info;
      };
      category queries { custom_log; };
    };

File Location: The ConfigMap data must have a key named.conf which will be mounted at /etc/bind/named.conf

configMapRefs.namedConfOptions

Type: string Required: No

Name of ConfigMap containing the named.conf.options file.

spec:
  configMapRefs:
    namedConfOptions: "my-options"

ConfigMap Format:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-options
  namespace: bindy-system
data:
  named.conf.options: |
    options {
      directory "/var/cache/bind";
      recursion no;
      allow-query { any; };
      dnssec-validation auto;
    };

File Location: The ConfigMap data must have a key named.conf.options which will be mounted at /etc/bind/named.conf.options

Examples:

Using separate ConfigMaps for fine-grained control:

spec:
  configMapRefs:
    namedConf: "prod-named-conf"
    namedConfOptions: "prod-options"

Using only custom options, auto-generating main config:

spec:
  configMapRefs:
    namedConfOptions: "my-custom-options"
  # namedConf not specified - will be auto-generated

global

Type: object Required: No

BIND9 configuration options that override cluster-level global configuration.

global.recursion

Type: boolean Required: No Default: false

Enable recursive DNS queries. Should be false for authoritative servers.

spec:
  global:
    recursion: false

Warning: Enabling recursion on public-facing authoritative servers is a security risk.

global.allowQuery

Type: array of strings Required: No Default: ["0.0.0.0/0"]

IP addresses or CIDR blocks allowed to query this server.

spec:
  global:
    allowQuery:
      - "0.0.0.0/0"        # Allow all (public DNS)
      - "10.0.0.0/8"       # Private network
      - "192.168.1.0/24"   # Specific subnet

global.allowTransfer

Type: array of strings Required: No Default: []

IP addresses or CIDR blocks allowed to perform zone transfers (AXFR/IXFR).

spec:
  global:
    allowTransfer:
      - "10.0.1.10"        # Specific secondary server
      - "10.0.1.11"        # Another secondary

Security Note: Restrict zone transfers to trusted secondary servers only.

global.dnssec

Type: object Required: No

DNSSEC configuration for signing zones and validating responses.

global.dnssec.enabled

Type: boolean Required: No Default: false

Enable DNSSEC signing for zones.

spec:
  global:
    dnssec:
      enabled: true
global.dnssec.validation

Type: boolean Required: No Default: false

Enable DNSSEC validation for recursive queries.

spec:
  global:
    dnssec:
      enabled: true
      validation: true

global.forwarders

Type: array of strings Required: No Default: []

DNS servers to forward queries to (for recursive mode).

spec:
  global:
    recursion: true
    forwarders:
      - "8.8.8.8"
      - "8.8.4.4"

global.listenOn

Type: array of strings Required: No Default: ["any"]

IPv4 addresses to listen on.

spec:
  global:
    listenOn:
      - "any"              # All IPv4 interfaces
      - "10.0.1.10"        # Specific IP

global.listenOnV6

Type: array of strings Required: No Default: ["any"]

IPv6 addresses to listen on.

spec:
  global:
    listenOnV6:
      - "any"              # All IPv6 interfaces
      - "2001:db8::1"      # Specific IPv6

global.rateLimit

Type: object Required: No Default: responsesPerSecond: 15 (Response Rate Limiting is on by default)

Configures BIND9 Response Rate Limiting (RRL), which throttles identical authoritative responses per client source prefix (an IPv4 /24 by default) to mitigate DNS amplification and reflection attacks. Because it applies only to authoritative answers and is scoped per source prefix, the conservative default rarely affects legitimate clients.

Rendered into named.conf.options as rate-limit { responses-per-second N; }. Set responsesPerSecond: 0 to disable RRL entirely (no rate-limit block is emitted). Instance-level spec.config.rateLimit overrides the cluster global.rateLimit value.

spec:
  global:
    rateLimit:
      responsesPerSecond: 20   # Tune the cap; omit the block to use the default (15)
spec:
  config:
    rateLimit:
      responsesPerSecond: 0    # Disable RRL for this instance

Status Fields

conditions

Type: array of objects

Standard Kubernetes conditions indicating resource state.

status:
  conditions:
    - type: Ready
      status: "True"
      reason: ReconcileSuccess
      message: "Instance is ready"
      lastTransitionTime: "2024-01-15T10:30:00Z"

Condition Types: - Ready - Instance is ready for use - Available - Instance is serving DNS queries - Progressing - Instance is being reconciled - Degraded - Instance is partially functional - Failed - Instance reconciliation failed

observedGeneration

Type: integer

The generation of the resource that was last reconciled.

status:
  observedGeneration: 5

replicas

Type: integer

Total number of replicas configured.

status:
  replicas: 3

readyReplicas

Type: integer

Number of replicas that are ready and serving traffic.

status:
  readyReplicas: 3

Complete Example

Primary DNS Instance

# First create the Bind9Cluster
apiVersion: bindy.firestoned.io/v1beta1
kind: Bind9Cluster
metadata:
  name: production-dns
  namespace: bindy-system
spec:
  version: "9.18"
  global:
    recursion: false
    allowQuery:
      - "0.0.0.0/0"
    allowTransfer:
      - "10.0.2.0/24"
    dnssec:
      enabled: true

---
# Then create the Bind9Instance referencing the cluster
apiVersion: bindy.firestoned.io/v1beta1
kind: Bind9Instance
metadata:
  name: primary-dns
  namespace: bindy-system
  labels:
    dns-role: primary
    environment: production
spec:
  clusterRef: production-dns  # References cluster above
  role: primary  # Required: primary or secondary
  replicas: 2
  # Inherits version and global config from cluster

Secondary DNS Instance

apiVersion: bindy.firestoned.io/v1beta1
kind: Bind9Instance
metadata:
  name: secondary-dns
  namespace: bindy-system
  labels:
    dns-role: secondary
    environment: production
spec:
  clusterRef: production-dns  # References same cluster as primary
  role: secondary  # Required: primary or secondary
  replicas: 2
  # Override global config for secondary role
  global:
    allowTransfer: []  # No zone transfers from secondary
    dnssec:
      enabled: false
      validation: true

Recursive Resolver

# Separate cluster for resolvers
apiVersion: bindy.firestoned.io/v1beta1
kind: Bind9Cluster
metadata:
  name: resolver-cluster
  namespace: bindy-system
spec:
  version: "9.18"
  global:
    recursion: true
    allowQuery:
      - "10.0.0.0/8"  # Internal network only
    forwarders:
      - "8.8.8.8"
      - "1.1.1.1"
    dnssec:
      enabled: false
      validation: true

---
apiVersion: bindy.firestoned.io/v1beta1
kind: Bind9Instance
metadata:
  name: resolver
  namespace: bindy-system
  labels:
    dns-role: resolver
spec:
  clusterRef: resolver-cluster
  role: primary  # Required: primary or secondary
  replicas: 3
  # Inherits recursive global config from cluster