Fix authoritative secondary replication (TSIG transfer + stable primary)
Secondaries never replicated any member zone: the master's catalog zone
requires key-authenticated AXFR (allow-transfer { key "transfer-key"; }),
but the rendered secondary config transferred without presenting the key,
so every catalog transfer was REFUSED and no member zones provisioned.
Two further gaps compounded it: member zones had no allow-transfer at all,
and secondaries pointed at the primary's pod IP, which dies on restart.
- Render the catalog transfer key into the secondary catalog-zones
default-primaries and the secondary catalog zone primaries, so
key-authenticated AXFR from the primary is accepted.
- Add allow-transfer { key "<transfer-key>"; } to catalog member primary
zones (when the zone does not set an explicit allow-transfer), so
secondaries can pull them; applied to existing zones via modzone.
- Point secondaries at the stable primary Service ClusterIP instead of the
primary pod IP, so replication survives primary pod restarts (falls back
to the pod IP when no primary Service exists).
This commit is contained in:
@@ -80,7 +80,7 @@ func (r *BindZoneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
|
||||
return r.setPhase(ctx, &zone, "Pending", "PrimaryNotReady", "waiting for cluster primary to be ready")
|
||||
}
|
||||
|
||||
zoneConfig, err := r.buildZoneConfig(ctx, &zone)
|
||||
zoneConfig, err := r.buildZoneConfig(ctx, &zone, r.zoneTransferKeyRef(ctx, &zone, cluster))
|
||||
if err != nil {
|
||||
return r.setPhase(ctx, &zone, "Error", "ConfigError", err.Error())
|
||||
}
|
||||
@@ -133,7 +133,9 @@ func (r *BindZoneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
|
||||
}
|
||||
|
||||
// buildZoneConfig renders the inner clause passed to rndc addzone/modzone.
|
||||
func (r *BindZoneReconciler) buildZoneConfig(ctx context.Context, zone *bindv1alpha1.BindZone) (string, error) {
|
||||
// transferKey, when set, is the catalog transfer TSIG key name; catalog member
|
||||
// primary zones must allow AXFR with it so secondaries can pull them.
|
||||
func (r *BindZoneReconciler) buildZoneConfig(ctx context.Context, zone *bindv1alpha1.BindZone, transferKey string) (string, error) {
|
||||
zType := zone.Spec.Type
|
||||
if zType == "" {
|
||||
zType = bindv1alpha1.ZonePrimary
|
||||
@@ -145,8 +147,12 @@ func (r *BindZoneReconciler) buildZoneConfig(ctx context.Context, zone *bindv1al
|
||||
if zone.Spec.DynamicUpdate && zone.Spec.UpdateKeyRef != "" {
|
||||
parts = append(parts, fmt.Sprintf("allow-update { key \"%s\"; }", updateKeyName(ctx, r.Client, zone)))
|
||||
}
|
||||
if len(zone.Spec.AllowTransfer) > 0 {
|
||||
switch {
|
||||
case len(zone.Spec.AllowTransfer) > 0:
|
||||
parts = append(parts, fmt.Sprintf("allow-transfer { %s }", matchListInline(zone.Spec.AllowTransfer)))
|
||||
case transferKey != "":
|
||||
// Catalog member: permit key-authenticated AXFR from secondaries.
|
||||
parts = append(parts, fmt.Sprintf("allow-transfer { key \"%s\"; }", transferKey))
|
||||
}
|
||||
if zone.Spec.DNSSECPolicyRef != "" {
|
||||
parts = append(parts, fmt.Sprintf("dnssec-policy \"%s\"", zone.Spec.DNSSECPolicyRef), "inline-signing yes")
|
||||
@@ -202,6 +208,26 @@ func (r *BindZoneReconciler) deregisterCatalog(ctx context.Context, zone *bindv1
|
||||
_ = r.Exec.RemoveCatalogMember(ctx, zone.Namespace, primaryPod, catalog.Spec.ZoneName, zone.Spec.ZoneName, creds)
|
||||
}
|
||||
|
||||
// zoneTransferKeyRef returns the catalog transfer TSIG key name that a catalog
|
||||
// member primary zone must allow AXFR with, so secondaries (which present that
|
||||
// key) can pull it. Returns "" for non-member zones, non-primary zones, or when
|
||||
// the cluster has no catalog.
|
||||
func (r *BindZoneReconciler) zoneTransferKeyRef(ctx context.Context, zone *bindv1alpha1.BindZone, cluster *bindv1alpha1.BindCluster) string {
|
||||
if !isPrimaryType(zone.Spec.Type) || !catalogEnabled(zone) {
|
||||
return ""
|
||||
}
|
||||
var catalogs bindv1alpha1.BindCatalogZoneList
|
||||
if err := r.List(ctx, &catalogs, client.InNamespace(zone.Namespace)); err != nil {
|
||||
return ""
|
||||
}
|
||||
for i := range catalogs.Items {
|
||||
if catalogs.Items[i].Spec.ClusterRef == cluster.Name {
|
||||
return catalogs.Items[i].Spec.TransferKeyRef
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *BindZoneReconciler) catalogFor(ctx context.Context, zone *bindv1alpha1.BindZone, cluster *bindv1alpha1.BindCluster) (*bindv1alpha1.BindCatalogZone, bind.TSIGCreds, bool) {
|
||||
var catalogs bindv1alpha1.BindCatalogZoneList
|
||||
if err := r.List(ctx, &catalogs, client.InNamespace(zone.Namespace)); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user