pub struct DNSZoneSpec {
pub zone_name: String,
pub soa_record: SOARecord,
pub ttl: Option<i32>,
pub cluster_ref: Option<String>,
pub name_servers: Option<Vec<NameServer>>,
pub name_server_ips: Option<HashMap<String, String>>,
pub records_from: Option<Vec<RecordSource>>,
pub bind9_instances_from: Option<Vec<InstanceSource>>,
pub dnssec_policy: Option<String>,
}Expand description
DNSZone defines a DNS zone to be managed by BIND9.
A DNSZone represents an authoritative DNS zone (e.g., example.com) that will be
served by a BIND9 cluster. The zone includes SOA record information and will be
synchronized to all instances in the referenced cluster via AXFR/IXFR.
DNSZones can reference either:
- A namespace-scoped
Bind9Cluster(usingclusterRef) - A cluster-scoped
ClusterBind9Provider(usingclusterProviderRef)
Exactly one of clusterRef or clusterProviderRef must be specified.
§Example: Namespace-scoped Cluster
apiVersion: bindy.firestoned.io/v1beta1
kind: DNSZone
metadata:
name: example-com
namespace: dev-team-alpha
spec:
zoneName: example.com
clusterRef: dev-team-dns # References Bind9Cluster in same namespace
soaRecord:
primaryNs: ns1.example.com.
adminEmail: admin.example.com.
serial: 2024010101
refresh: 3600
retry: 600
expire: 604800
negativeTtl: 86400
ttl: 3600§Example: Cluster-scoped Global Cluster
apiVersion: bindy.firestoned.io/v1beta1
kind: DNSZone
metadata:
name: production-example-com
namespace: production
spec:
zoneName: example.com
clusterProviderRef: shared-production-dns # References ClusterBind9Provider (cluster-scoped)
soaRecord:
primaryNs: ns1.example.com.
adminEmail: admin.example.com.
serial: 2024010101
refresh: 3600
retry: 600
expire: 604800
negativeTtl: 86400
ttl: 3600Fields§
§zone_name: StringDNS zone name (e.g., “example.com”).
Must be a valid DNS zone name. Can be a domain or subdomain. Examples: “example.com”, “internal.example.com”, “10.in-addr.arpa”
soa_record: SOARecordSOA (Start of Authority) record - defines zone authority and refresh parameters.
The SOA record is required for all authoritative zones and contains timing information for zone transfers and caching.
ttl: Option<i32>Default TTL (Time To Live) for records in this zone, in seconds.
If not specified, individual records must specify their own TTL. Typical values: 300-86400 (5 minutes to 1 day).
cluster_ref: Option<String>Reference to a Bind9Cluster or ClusterBind9Provider to serve this zone.
When specified, this zone will be automatically configured on all Bind9Instance
resources that belong to the referenced cluster. This provides a simple way to
assign zones to entire clusters.
Relationship with bind9_instances_from:
- If only
cluster_refis specified: Zone targets all instances in that cluster - If only
bind9_instances_fromis specified: Zone targets instances matching label selectors - If both are specified: Zone targets union of cluster instances AND label-selected instances
§Example
spec:
clusterRef: production-dns # Target all instances in this cluster
zoneName: example.comname_servers: Option<Vec<NameServer>>Authoritative nameservers for this zone (v0.4.0+).
NS records are automatically generated at the zone apex (@) for all entries.
The primary nameserver from soaRecord.primaryNs is always included automatically.
Each entry can optionally include IP addresses to generate glue records (A/AAAA) for in-zone nameservers. Glue records are required when the nameserver is within the zone’s own domain to avoid circular dependencies.
§Examples
# In-zone nameservers with glue records
nameServers:
- hostname: ns2.example.com.
ipv4Address: "192.0.2.2"
- hostname: ns3.example.com.
ipv4Address: "192.0.2.3"
ipv6Address: "2001:db8::3"
# Out-of-zone nameserver (no glue needed)
- hostname: ns4.external-provider.net.Generated Records:
@ IN NS ns2.example.com.(NS record)ns2.example.com. IN A 192.0.2.2(glue record for in-zone NS)@ IN NS ns3.example.com.(NS record)ns3.example.com. IN A 192.0.2.3(IPv4 glue)ns3.example.com. IN AAAA 2001:db8::3(IPv6 glue)@ IN NS ns4.external-provider.net.(NS record only, no glue)
Benefits over nameServerIps (deprecated):
- Clearer purpose: authoritative nameservers, not just glue records
- IPv6 support via
ipv6Addressfield - Automatic NS record generation (no manual
NSRecordCRs needed)
Migration: See docs/src/operations/migration-guide.md
name_server_ips: Option<HashMap<String, String>>name_servers instead. This field will be removed in v1.0.0. See migration guide at docs/src/operations/migration-guide.md(DEPRECATED in v0.4.0) Map of nameserver hostnames to IP addresses for glue records.
Use nameServers instead. This field will be removed in v1.0.0.
Glue records provide IP addresses for nameservers within the zone’s own domain. This is necessary when delegating subdomains where the nameserver is within the delegated zone itself.
Example: When delegating sub.example.com with nameserver ns1.sub.example.com,
you must provide the IP address of ns1.sub.example.com as a glue record.
Format: {"ns1.example.com.": "192.0.2.1", "ns2.example.com.": "192.0.2.2"}
Note: Nameserver hostnames should end with a dot (.) for FQDN.
Migration to nameServers:
# Old (deprecated):
nameServerIps:
ns2.example.com.: "192.0.2.2"
# New (recommended):
nameServers:
- hostname: ns2.example.com.
ipv4Address: "192.0.2.2"records_from: Option<Vec<RecordSource>>Sources for DNS records to include in this zone.
This field defines label selectors that automatically associate DNS records with this zone. Records with matching labels will be included in the zone’s DNS configuration.
This follows the standard Kubernetes selector pattern used by Services, NetworkPolicies,
and other resources for declarative resource association.
§Example: Match podinfo records in dev/staging environments
recordsFrom:
- selector:
matchLabels:
app: podinfo
matchExpressions:
- key: environment
operator: In
values:
- dev
- staging§Selector Operators
- In: Label value must be in the specified values list
NotIn: Label value must NOT be in the specified values list- Exists: Label key must exist (any value)
DoesNotExist: Label key must NOT exist
§Use Cases
- Multi-environment zones: Dynamically include records based on environment labels
- Application-specific zones: Group all records for an application using
applabel - Team-based zones: Use team labels to automatically route records to team-owned zones
- Temporary records: Use labels to include/exclude records without changing
zoneRef
bind9_instances_from: Option<Vec<InstanceSource>>Select Bind9Instance resources to target for zone configuration using label selectors.
This field enables dynamic, label-based selection of DNS instances to serve this zone.
Instances matching these selectors will automatically receive zone configuration from
the DNSZone controller.
This follows the standard Kubernetes selector pattern used by Services, NetworkPolicies,
and other resources for declarative resource association.
IMPORTANT: This is the preferred method for zone-instance association. It provides:
- Decoupled Architecture: Zones select instances, not vice versa
- Zone Ownership: Zone authors control which instances serve their zones
- Dynamic Scaling: New instances matching labels automatically pick up zones
- Multi-Tenancy: Zones can target specific instance groups (prod, staging, team-specific)
§Example: Target production primary instances
apiVersion: bindy.firestoned.io/v1beta1
kind: DNSZone
metadata:
name: example-com
namespace: bindy-system
spec:
zoneName: example.com
bind9InstancesFrom:
- selector:
matchLabels:
environment: production
bindy.firestoned.io/role: primary§Example: Target instances by region and tier
bind9InstancesFrom:
- selector:
matchLabels:
tier: frontend
atchExpressions:
- key: region
operator: In
values:
- us-east-1
- us-west-2§Selector Operators
- In: Label value must be in the specified values list
NotIn: Label value must NOT be in the specified values list- Exists: Label key must exist (any value)
DoesNotExist: Label key must NOT exist
§Use Cases
- Environment Isolation: Target only production instances (
environment: production) - Role-Based Selection: Select only primary or secondary instances
- Geographic Distribution: Target instances in specific regions
- Team Boundaries: Select instances managed by specific teams
- Testing Zones: Target staging instances for non-production zones
§Relationship with clusterRef
clusterRef: Explicitly assigns zone to ALL instances in a clusterbind9InstancesFrom: Dynamically selects specific instances using labels (more flexible)
You can use both approaches together - the zone will target the union of:
- All instances in
clusterRefcluster - Plus any additional instances matching
bind9InstancesFromselectors
§Event-Driven Architecture
The DNSZone controller watches both DNSZone and Bind9Instance resources.
When labels change on either:
- Controller re-evaluates label selector matching
- Automatically configures zones on newly-matched instances
- Removes zone configuration from instances that no longer match
dnssec_policy: Option<String>Override DNSSEC policy for this zone
Allows per-zone override of the cluster’s global DNSSEC signing policy.
If not specified, the zone inherits the DNSSEC configuration from the
cluster’s global.dnssec.signing.policy.
Use this to:
- Disable signing for specific zones in a signing-enabled cluster
- Use stricter security policies for sensitive zones
- Test different signing algorithms on specific zones
§Example: Custom High-Security Policy
apiVersion: bindy.firestoned.io/v1beta1
kind: DNSZone
metadata:
name: secure-zone
spec:
zoneName: secure.example.com
clusterRef: production-dns
dnssecPolicy: "high-security" # Override cluster default§Example: Disable Signing for One Zone
dnssecPolicy: "none" # Disable signing (cluster has signing enabled)Note: Custom policies require BIND9 dnssec-policy configuration.
Built-in policies: "default", "none"
Trait Implementations§
Source§impl Clone for DNSZoneSpec
impl Clone for DNSZoneSpec
Source§fn clone(&self) -> DNSZoneSpec
fn clone(&self) -> DNSZoneSpec
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for DNSZoneSpec
impl Debug for DNSZoneSpec
Source§impl<'de> Deserialize<'de> for DNSZoneSpec
impl<'de> Deserialize<'de> for DNSZoneSpec
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for DNSZoneSpec
impl JsonSchema for DNSZoneSpec
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl Freeze for DNSZoneSpec
impl RefUnwindSafe for DNSZoneSpec
impl Send for DNSZoneSpec
impl Sync for DNSZoneSpec
impl Unpin for DNSZoneSpec
impl UnwindSafe for DNSZoneSpec
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].