mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2026-04-18 14:31:18 +02:00
760 lines
23 KiB
Markdown
760 lines
23 KiB
Markdown
# RFC2136 provider
|
||
|
||
This tutorial describes how to use the RFC2136 with either BIND or Windows DNS.
|
||
|
||
## Deploying BIND9 on Kubernetes with Kind
|
||
|
||
This section walks through deploying BIND9 and ExternalDNS inside a local Kubernetes cluster using [Kind](https://kind.sigs.k8s.io/). It provides a self-contained lab environment for testing the RFC2136 provider, including forward and reverse (PTR) DNS zones with TSIG authentication.
|
||
|
||
### TL;DR
|
||
|
||
After completing this lab, you will have a local Kubernetes cluster running BIND9 and ExternalDNS with:
|
||
|
||
- A forward zone (`example.local`) for A records
|
||
- A reverse zone (`49.168.192.in-addr.arpa`) for PTR records
|
||
- TSIG-authenticated dynamic DNS updates
|
||
- ExternalDNS automatically creating and managing DNS records
|
||
|
||
### Notes
|
||
|
||
- BIND9 runs inside the cluster for demonstration purposes.
|
||
- For production deployments, use an external BIND server with proper security hardening.
|
||
- The zones and TSIG key are preconfigured — adapt them to your environment.
|
||
|
||
### Prerequisites
|
||
|
||
Before you start, ensure you have:
|
||
|
||
- [Kind](https://kind.sigs.k8s.io/) installed
|
||
- [`kubectl`](https://kubernetes.io/docs/tasks/tools/) and [`helm`](https://helm.sh/)
|
||
- [`dig`](https://linux.die.net/man/1/dig) for DNS queries (optional, for verification)
|
||
|
||
### 1. Create the Kind cluster
|
||
|
||
```sh
|
||
kind create cluster --config=docs/snippets/tutorials/rfc2136/kind.yaml
|
||
|
||
Creating cluster "rfc2136-bind9" ...
|
||
✓ Ensuring node image (kindest/node:v1.35.1) 🖼
|
||
✓ Preparing nodes 📦 📦
|
||
✓ Writing configuration 📜
|
||
✓ Starting control-plane 🕹️
|
||
✓ Installing CNI 🔌
|
||
✓ Installing StorageClass 💾
|
||
✓ Joining worker nodes 🚜
|
||
Set kubectl context to "kind-rfc2136-bind9"
|
||
```
|
||
|
||
The Kind configuration exposes port `30053` on the host as `5354`, allowing DNS queries from your machine against BIND9 running inside the cluster.
|
||
|
||
### 2. Deploy BIND9
|
||
|
||
The BIND9 manifest deploys a ConfigMap with `named.conf`, forward and reverse zone files, a Deployment, and Services (ClusterIP + NodePort).
|
||
|
||
The configuration includes:
|
||
|
||
- **Forward zone** (`example.local`): accepts dynamic updates authenticated with the `externaldns-key` TSIG key
|
||
- **Reverse zone** (`49.168.192.in-addr.arpa`): accepts dynamic updates and zone transfers with the same TSIG key
|
||
|
||
```sh
|
||
kubectl apply -f docs/snippets/tutorials/rfc2136/bind9.yaml
|
||
|
||
kubectl rollout status deployment/bind9 -n bind9
|
||
|
||
❯❯ deployment "bind9" successfully rolled out
|
||
```
|
||
|
||
Verify BIND9 is running:
|
||
|
||
```sh
|
||
kubectl get pods -n bind9
|
||
|
||
❯❯ NAME READY STATUS RESTARTS AGE
|
||
❯❯ bind9-xxxxxxxxx-xxxxx 1/1 Running 0 30s
|
||
```
|
||
|
||
Check BIND9 logs for errors:
|
||
|
||
```sh
|
||
kubectl logs -n bind9 -l app=bind9 --tail=20
|
||
```
|
||
|
||
### 3. Deploy ExternalDNS with Helm
|
||
|
||
Add the ExternalDNS Helm repository:
|
||
|
||
```sh
|
||
helm repo add --force-update external-dns https://kubernetes-sigs.github.io/external-dns/
|
||
```
|
||
|
||
Install ExternalDNS with the RFC2136 provider configuration:
|
||
|
||
```sh
|
||
helm upgrade --install external-dns external-dns/external-dns \
|
||
-f docs/snippets/tutorials/rfc2136/values-extdns-rfc2136.yaml \
|
||
-n default
|
||
|
||
❯❯ Release "external-dns" does not exist. Installing it now.
|
||
```
|
||
|
||
Validate pod status and view logs:
|
||
|
||
```sh
|
||
kubectl get pods -l app.kubernetes.io/name=external-dns
|
||
|
||
kubectl logs deploy/external-dns --tail=50
|
||
```
|
||
|
||
Or run ExternalDNS from source on the host (requires the NodePort to be accessible):
|
||
|
||
```sh
|
||
go run main.go \
|
||
--provider=rfc2136 \
|
||
--rfc2136-host=127.0.0.1 \
|
||
--rfc2136-port=5354 \
|
||
--rfc2136-zone=example.local \
|
||
--rfc2136-zone=49.168.192.in-addr.arpa \
|
||
--rfc2136-tsig-keyname=externaldns-key \
|
||
--rfc2136-tsig-secret=96Ah/a2g0/nLeFGK+d/0tzQcccf9hCEIy34PoXX2Qg8= \
|
||
--rfc2136-tsig-secret-alg=hmac-sha256 \
|
||
--rfc2136-tsig-axfr \
|
||
--create-ptr \
|
||
--source=crd \
|
||
--source=service \
|
||
--domain-filter=example.local \
|
||
--domain-filter=49.168.192.in-addr.arpa \
|
||
--managed-record-types=A \
|
||
--managed-record-types=AAAA \
|
||
--managed-record-types=CNAME \
|
||
--managed-record-types=PTR \
|
||
--policy=sync \
|
||
--log-level=debug
|
||
```
|
||
|
||
### 4. Create test DNS records
|
||
|
||
Apply the test fixtures which include DNSEndpoint CRDs and a LoadBalancer Service:
|
||
|
||
```sh
|
||
kubectl apply -f docs/snippets/tutorials/rfc2136/fixtures.yaml
|
||
```
|
||
|
||
If using Service sources, patch the LoadBalancer to simulate an external IP assignment:
|
||
|
||
```sh
|
||
kubectl patch svc nginx-rfc2136 --type=merge \
|
||
-p '{"status":{"loadBalancer":{"ingress":[{"ip":"192.168.49.50"}]}}}' \
|
||
--subresource=status
|
||
|
||
❯❯ service/nginx-rfc2136 patched
|
||
```
|
||
|
||
Wait for ExternalDNS to sync (check the logs for update activity):
|
||
|
||
```sh
|
||
kubectl logs deploy/external-dns --tail=30 -f
|
||
```
|
||
|
||
### 5. Verify DNS records
|
||
|
||
Query the forward zone for A records:
|
||
|
||
```sh
|
||
dig @127.0.0.1 -p 5354 +tcp app.example.local A +short
|
||
❯❯ 192.168.49.10
|
||
|
||
dig @127.0.0.1 -p 5354 +tcp api.example.local A +short
|
||
❯❯ 192.168.49.20
|
||
|
||
dig @127.0.0.1 -p 5354 +tcp svc.example.local A +short
|
||
❯❯ 192.168.49.50
|
||
```
|
||
|
||
Query the reverse zone for PTR records:
|
||
|
||
```sh
|
||
dig @127.0.0.1 -p 5354 +tcp -x 192.168.49.10 +short
|
||
❯❯ app.example.local.
|
||
|
||
dig @127.0.0.1 -p 5354 +tcp -x 192.168.49.20 +short
|
||
❯❯ api.example.local.
|
||
```
|
||
|
||
List all records in the reverse zone via AXFR (requires the TSIG key since zone transfers are restricted):
|
||
|
||
```sh
|
||
dig @127.0.0.1 -p 5354 +tcp 49.168.192.in-addr.arpa. AXFR \
|
||
-y hmac-sha256:externaldns-key:96Ah/a2g0/nLeFGK+d/0tzQcccf9hCEIy34PoXX2Qg8= \
|
||
+noall +answer
|
||
```
|
||
|
||
Alternatively, query from inside the cluster using a debug pod:
|
||
|
||
```sh
|
||
kubectl run --rm -it dnsutils --image=infoblox/dnstools --restart=Never
|
||
|
||
dig +short @bind9.bind9.svc.cluster.local app.example.local
|
||
❯❯ 192.168.49.10
|
||
|
||
dig +short @bind9.bind9.svc.cluster.local -x 192.168.49.10
|
||
❯❯ app.example.local.
|
||
```
|
||
|
||
### 6. Cleanup
|
||
|
||
```sh
|
||
kind delete cluster --name rfc2136-bind9
|
||
```
|
||
|
||
## Using with BIND
|
||
|
||
To use external-dns with BIND: generate/procure a key, configure DNS and add a
|
||
deployment of external-dns.
|
||
|
||
### Server credentials
|
||
|
||
- RFC2136 was developed for and tested with [BIND](https://www.isc.org/downloads/bind/) DNS server.
|
||
This documentation assumes that you already have a configured and working server. If you don't,
|
||
please check BIND documents or tutorials.
|
||
- If your DNS is provided for you, ask for a TSIG key authorized to update and
|
||
transfer the zone you wish to update. The key will look something like below.
|
||
Skip the next steps wrt BIND setup.
|
||
|
||
```text
|
||
key "externaldns-key" {
|
||
algorithm hmac-sha256;
|
||
secret "96Ah/a2g0/nLeFGK+d/0tzQcccf9hCEIy34PoXX2Qg8=";
|
||
};
|
||
```
|
||
|
||
- If you are your own DNS administrator create a TSIG key. Use
|
||
`tsig-keygen -a hmac-sha256 externaldns` or on older distributions
|
||
`dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST externaldns`. You will end up with
|
||
a key printed to standard out like above (or in the case of dnssec-keygen in a
|
||
file called `Kexternaldns......key`).
|
||
|
||
### BIND Configuration
|
||
|
||
If you do not administer your own DNS, skip to RFC provider configuration
|
||
|
||
- Edit your named.conf file (or appropriate included file) and add/change the
|
||
following.
|
||
- Make sure You are listening on the right interfaces. At least whatever
|
||
interface external-dns will be communicating over and the interface that
|
||
faces the internet.
|
||
- Add the key that you generated/was given to you above. Copy paste the four
|
||
lines that you got (not the same as the example key) into your file.
|
||
- Make sure zone transfer is enabled for the key, this enables listing all
|
||
records
|
||
- Create a zone for kubernetes. If you already have a zone, skip to the next
|
||
step. (I put the zone in it's own subdirectory because named,
|
||
which shouldn't be running as root, needs to create a journal file and the
|
||
default zone directory isn't writeable by named).
|
||
|
||
```text
|
||
zone "k8s.example.org" {
|
||
type master;
|
||
file "/etc/bind/pri/k8s/k8s.zone";
|
||
};
|
||
```
|
||
|
||
- Add your key to both transfer and update. For instance with our previous
|
||
zone.
|
||
|
||
```text
|
||
zone "k8s.example.org" {
|
||
type master;
|
||
file "/etc/bind/pri/k8s/k8s.zone";
|
||
allow-transfer {
|
||
key "externaldns-key";
|
||
};
|
||
update-policy {
|
||
grant externaldns-key zonesub ANY;
|
||
};
|
||
};
|
||
```
|
||
|
||
- Create a zone file (k8s.zone):
|
||
|
||
```text
|
||
$TTL 60 ; 1 minute
|
||
k8s.example.org IN SOA k8s.example.org. root.k8s.example.org. (
|
||
16 ; serial
|
||
60 ; refresh (1 minute)
|
||
60 ; retry (1 minute)
|
||
60 ; expire (1 minute)
|
||
60 ; minimum (1 minute)
|
||
)
|
||
NS ns.k8s.example.org.
|
||
ns A 123.456.789.012
|
||
```
|
||
|
||
- Reload (or restart) named
|
||
|
||
### AXFR and the sync policy
|
||
|
||
When using the `sync` policy, ExternalDNS requires AXFR (zone transfer) to be
|
||
explicitly enabled via the `--rfc2136-tsig-axfr` flag. This is necessary for
|
||
ExternalDNS to list all existing DNS records and determine which ones should be
|
||
lifecycled.
|
||
|
||
Without `--rfc2136-tsig-axfr`, ExternalDNS cannot list records and will act as
|
||
if the policy was set to `upsert-only`. No warning will be provided.
|
||
|
||
### Using external-dns
|
||
|
||
To use external-dns add an ingress or a LoadBalancer service with a host that
|
||
is part of the domain-filter. For example both of the following would produce
|
||
A records.
|
||
|
||
```text
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: nginx
|
||
annotations:
|
||
external-dns.alpha.kubernetes.io/hostname: svc.example.org
|
||
spec:
|
||
type: LoadBalancer
|
||
ports:
|
||
- port: 80
|
||
targetPort: 80
|
||
selector:
|
||
app: nginx
|
||
---
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: Ingress
|
||
metadata:
|
||
name: my-ingress
|
||
spec:
|
||
rules:
|
||
- host: ingress.example.org
|
||
http:
|
||
paths:
|
||
- path: /
|
||
backend:
|
||
serviceName: my-service
|
||
servicePort: 8000
|
||
```
|
||
|
||
### Custom TTL
|
||
|
||
The default DNS record TTL (Time-To-Live) is 0 seconds. You can customize this value by setting the annotation `external-dns.alpha.kubernetes.io/ttl`. e.g., modify the service manifest YAML file above:
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: nginx
|
||
annotations:
|
||
external-dns.alpha.kubernetes.io/hostname: nginx.external-dns-test.my-org.com
|
||
external-dns.alpha.kubernetes.io/ttl: 60
|
||
spec:
|
||
...
|
||
```
|
||
|
||
This will set the DNS record's TTL to 60 seconds.
|
||
|
||
A default TTL for all records can be set using the the flag with a time in seconds, minutes or hours, such as `--rfc2136-min-ttl=60s`
|
||
|
||
There are other annotation that can affect the generation of DNS records, but these are beyond the scope of this
|
||
tutorial and are covered in the main documentation.
|
||
|
||
### Generate reverse DNS records
|
||
|
||
> **Note:** The `--rfc2136-create-ptr` flag is removed. Use the generic `--create-ptr` flag instead.
|
||
|
||
ExternalDNS can automatically create PTR records for your A/AAAA records. This is a generic feature
|
||
that works with any provider, not just RFC2136. For RFC2136 you also need to add the reverse zone to
|
||
`--rfc2136-zone`:
|
||
|
||
```sh
|
||
--create-ptr --domain-filter=157.168.192.in-addr.arpa --rfc2136-zone=157.168.192.in-addr.arpa
|
||
```
|
||
|
||
See [Automatic PTR (Reverse DNS) Records](../advanced/ptr-records.md) for full documentation
|
||
including annotation overrides and behaviour details.
|
||
|
||
### Test with external-dns installed on local machine (optional)
|
||
|
||
You may install external-dns and test on a local machine by running:
|
||
|
||
```sh
|
||
external-dns --txt-owner-id k8s --provider rfc2136 \
|
||
--rfc2136-host=192.168.0.1 --rfc2136-port=53 \
|
||
--rfc2136-zone=k8s.example.org \
|
||
--rfc2136-tsig-secret=96Ah/a2g0/nLeFGK+d/0tzQcccf9hCEIy34PoXX2Qg8= \
|
||
--rfc2136-tsig-secret-alg=hmac-sha256 \
|
||
--rfc2136-tsig-keyname=externaldns-key \
|
||
--rfc2136-tsig-axfr \
|
||
--source ingress --once \
|
||
--domain-filter=k8s.example.org --dry-run
|
||
```
|
||
|
||
- host should be the IP of your master DNS server.
|
||
- tsig-secret should be changed to match your secret.
|
||
- tsig-keyname needs to match the keyname you used (if you changed it).
|
||
- domain-filter can be used as shown to filter the domains you wish to update.
|
||
|
||
### RFC2136 provider configuration
|
||
|
||
In order to use external-dns with your cluster you need to add a deployment
|
||
with access to your ingress and service resources. The following are two
|
||
example manifests with and without RBAC respectively.
|
||
|
||
- With RBAC:
|
||
|
||
```text
|
||
apiVersion: v1
|
||
kind: Namespace
|
||
metadata:
|
||
name: external-dns
|
||
labels:
|
||
name: external-dns
|
||
---
|
||
apiVersion: rbac.authorization.k8s.io/v1
|
||
kind: ClusterRole
|
||
metadata:
|
||
name: external-dns
|
||
namespace: external-dns
|
||
rules:
|
||
- apiGroups:
|
||
- ""
|
||
resources:
|
||
- services
|
||
- pods
|
||
- nodes
|
||
verbs:
|
||
- get
|
||
- watch
|
||
- list
|
||
- apiGroups:
|
||
- discovery.k8s.io
|
||
resources:
|
||
- endpointslices
|
||
verbs:
|
||
- get
|
||
- watch
|
||
- list
|
||
- apiGroups:
|
||
- extensions
|
||
- networking.k8s.io
|
||
resources:
|
||
- ingresses
|
||
verbs:
|
||
- get
|
||
- list
|
||
- watch
|
||
---
|
||
apiVersion: v1
|
||
kind: ServiceAccount
|
||
metadata:
|
||
name: external-dns
|
||
namespace: external-dns
|
||
---
|
||
apiVersion: rbac.authorization.k8s.io/v1
|
||
kind: ClusterRoleBinding
|
||
metadata:
|
||
name: external-dns-viewer
|
||
namespace: external-dns
|
||
roleRef:
|
||
apiGroup: rbac.authorization.k8s.io
|
||
kind: ClusterRole
|
||
name: external-dns
|
||
subjects:
|
||
- kind: ServiceAccount
|
||
name: external-dns
|
||
namespace: external-dns
|
||
---
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: external-dns
|
||
namespace: external-dns
|
||
spec:
|
||
selector:
|
||
matchLabels:
|
||
app: external-dns
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: external-dns
|
||
spec:
|
||
serviceAccountName: external-dns
|
||
containers:
|
||
- name: external-dns
|
||
image: registry.k8s.io/external-dns/external-dns:v0.21.0
|
||
args:
|
||
- --registry=txt
|
||
- --txt-prefix=external-dns-
|
||
- --txt-owner-id=k8s
|
||
- --provider=rfc2136
|
||
- --rfc2136-host=192.168.0.1
|
||
- --rfc2136-port=53
|
||
- --rfc2136-zone=k8s.example.org
|
||
- --rfc2136-zone=k8s.your-zone.org
|
||
- --rfc2136-tsig-secret=96Ah/a2g0/nLeFGK+d/0tzQcccf9hCEIy34PoXX2Qg8=
|
||
- --rfc2136-tsig-secret-alg=hmac-sha256
|
||
- --rfc2136-tsig-keyname=externaldns-key
|
||
- --rfc2136-tsig-axfr
|
||
- --source=ingress
|
||
- --domain-filter=k8s.example.org
|
||
```
|
||
|
||
- Without RBAC:
|
||
|
||
```text
|
||
apiVersion: v1
|
||
kind: Namespace
|
||
metadata:
|
||
name: external-dns
|
||
labels:
|
||
name: external-dns
|
||
---
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: external-dns
|
||
namespace: external-dns
|
||
spec:
|
||
selector:
|
||
matchLabels:
|
||
app: external-dns
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: external-dns
|
||
spec:
|
||
containers:
|
||
- name: external-dns
|
||
image: registry.k8s.io/external-dns/external-dns:v0.21.0
|
||
args:
|
||
- --registry=txt
|
||
- --txt-prefix=external-dns-
|
||
- --txt-owner-id=k8s
|
||
- --provider=rfc2136
|
||
- --rfc2136-host=192.168.0.1
|
||
- --rfc2136-port=53
|
||
- --rfc2136-zone=k8s.example.org
|
||
- --rfc2136-zone=k8s.your-zone.org
|
||
- --rfc2136-tsig-secret=96Ah/a2g0/nLeFGK+d/0tzQcccf9hCEIy34PoXX2Qg8=
|
||
- --rfc2136-tsig-secret-alg=hmac-sha256
|
||
- --rfc2136-tsig-keyname=externaldns-key
|
||
- --rfc2136-tsig-axfr
|
||
- --source=ingress
|
||
- --domain-filter=k8s.example.org
|
||
```
|
||
|
||
## Microsoft DNS
|
||
|
||
While `external-dns` was not developed or tested against Microsoft DNS, it can be configured to work against it. YMMV.
|
||
|
||
### Secure Updates Using RFC3645 (GSS-TSIG)
|
||
|
||
#### DNS-side configuration
|
||
|
||
1. Create a DNS zone
|
||
2. Enable **secure** dynamic updates for the zone
|
||
3. Enable Zone Transfers to all servers and/or other domains
|
||
4. Create a user with permissions to create/update/delete records in that zone
|
||
|
||
If you see any error messages which indicate that `external-dns` was somehow not able to fetch
|
||
existing DNS records from your DNS server, this could mean that you forgot about step 3.
|
||
|
||
##### Kerberos Configuration
|
||
|
||
DNS with secure updates relies upon a valid Kerberos configuration running within the `external-dns` container.
|
||
At this time, you will need to create a ConfigMap for the `external-dns` container to use and mount it in your deployment.
|
||
Below is an example of a working Kerberos configuration inside a ConfigMap definition. This may be different depending on many factors in your environment:
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
creationTimestamp: null
|
||
name: krb5.conf
|
||
data:
|
||
krb5.conf: |
|
||
[logging]
|
||
default = FILE:/var/log/krb5libs.log
|
||
kdc = FILE:/var/log/krb5kdc.log
|
||
admin_server = FILE:/var/log/kadmind.log
|
||
|
||
[libdefaults]
|
||
dns_lookup_realm = false
|
||
ticket_lifetime = 24h
|
||
renew_lifetime = 7d
|
||
forwardable = true
|
||
rdns = false
|
||
pkinit_anchors = /etc/pki/tls/certs/ca-bundle.crt
|
||
default_ccache_name = KEYRING:persistent:%{uid}
|
||
|
||
default_realm = YOUR-REALM.COM
|
||
|
||
[realms]
|
||
YOUR-REALM.COM = {
|
||
kdc = dc1.yourdomain.com
|
||
admin_server = dc1.yourdomain.com
|
||
}
|
||
|
||
[domain_realm]
|
||
yourdomain.com = YOUR-REALM.COM
|
||
.yourdomain.com = YOUR-REALM.COM
|
||
```
|
||
|
||
In most cases, the realm name will probably be the same as the domain name, so you can simply replace `YOUR-REALM.COM` with something like `YOURDOMAIN.COM`.
|
||
|
||
Once the ConfigMap is created, the container `external-dns` container needs to be told to mount that ConfigMap as a volume at the default Kerberos configuration location. The pod spec should include a similar configuration to the following:
|
||
|
||
```yaml
|
||
...
|
||
volumeMounts:
|
||
- mountPath: /etc/krb5.conf
|
||
name: kerberos-config-volume
|
||
subPath: krb5.conf
|
||
...
|
||
volumes:
|
||
- configMap:
|
||
defaultMode: 420
|
||
name: krb5.conf
|
||
name: kerberos-config-volume
|
||
...
|
||
```
|
||
|
||
##### `external-dns` configuration
|
||
|
||
You'll want to configure `external-dns` similarly to the following:
|
||
|
||
```text
|
||
...
|
||
- --provider=rfc2136
|
||
- --rfc2136-gss-tsig
|
||
- --rfc2136-host=dns-host.yourdomain.com
|
||
- --rfc2136-port=53
|
||
- --rfc2136-zone=your-zone.com
|
||
- --rfc2136-zone=your-secondary-zone.com
|
||
- --rfc2136-kerberos-username=your-domain-account
|
||
- --rfc2136-kerberos-password=your-domain-password
|
||
- --rfc2136-kerberos-realm=your-domain.com
|
||
- --rfc2136-tsig-axfr # needed to enable zone transfers, which is required for deletion of records.
|
||
...
|
||
```
|
||
|
||
As noted above, the `--rfc2136-kerberos-realm` flag is completely optional and won't be necessary in many cases.
|
||
Most likely, you will only need it if you see errors similar to this: `KRB Error: (68) KDC_ERR_WRONG_REALM Reserved for future use`.
|
||
|
||
The flag `--rfc2136-host` can be set to the host's domain name or IP address.
|
||
However, it also determines the name of the Kerberos principal which is used during authentication.
|
||
This means that Active Directory might only work if this is set to a specific domain name, possibly leading to errors like this:
|
||
`KDC_ERR_S_PRINCIPAL_UNKNOWN Server not found in Kerberos database`.
|
||
To fix this, try setting `--rfc2136-host` to the "actual" hostname of your DNS server.
|
||
|
||
### Insecure Updates
|
||
|
||
#### DNS-side configuration
|
||
|
||
1. Create a DNS zone
|
||
2. Enable insecure dynamic updates for the zone
|
||
3. Enable Zone Transfers to all servers and/or other domains
|
||
|
||
#### `external-dns` configuration
|
||
|
||
You'll want to configure `external-dns` similarly to the following:
|
||
|
||
```text
|
||
...
|
||
- --provider=rfc2136
|
||
- --rfc2136-host=192.168.0.1
|
||
- --rfc2136-port=53
|
||
- --rfc2136-zone=k8s.example.org
|
||
- --rfc2136-zone=k8s.your-zone.org
|
||
- --rfc2136-insecure
|
||
- --rfc2136-tsig-axfr # needed to enable zone transfers, which is required for deletion of records.
|
||
...
|
||
```
|
||
|
||
## DNS Over TLS (RFCs 7858 and 9103)
|
||
|
||
If your DNS server does zone transfers over TLS, you can instruct `external-dns` to connect over TLS with the following flags:
|
||
|
||
- `--rfc2136-use-tls` Will enable TLS for both zone transfers and for updates.
|
||
- `--tls-ca=<cert-file>` Is the path to a file containing certificate(s) that can be used to verify the DNS server
|
||
- `--tls-client-cert=<client-cert-file>` and
|
||
- `--tls-client-cert-key=<client-key-file>` Set the client certificate and key for mutual verification
|
||
- `--rfc2136-skip-tls-verify` Disables verification of the certificate supplied by the DNS server.
|
||
|
||
It is currently not supported to do only zone transfers over TLS, but not the updates. They are enabled and disabled together.
|
||
|
||
## Configuring RFC2136 Provider with Multiple Hosts and Load Balancing
|
||
|
||
This section describes how to configure the RFC2136 provider in ExternalDNS to support multiple DNS servers and load balancing options.
|
||
|
||
### Enhancements Overview
|
||
|
||
The RFC2136 provider now supports multiple DNS hosts and introduces load balancing options to distribute DNS update requests evenly across available DNS servers. This helps prevent a single server from becoming a bottleneck in environments with multiple DNS servers.
|
||
|
||
### Configuration Steps
|
||
|
||
1. **Allow Multiple Hosts for `--rfc2136-host`**
|
||
- Modify the `--rfc2136-host` command-line option to accept multiple hosts.
|
||
- Example: `--rfc2136-host="dns-host-1.yourdomain.com" --rfc2136-host="dns-host-2.yourdomain.com"`
|
||
|
||
2. **Introduce Load Balancing Options**
|
||
- Add a new command-line option `--rfc2136-load-balancing-strategy` to specify the load balancing strategy.
|
||
- Supported options:
|
||
- `round-robin`: Distributes DNS updates evenly across all specified hosts in a round-robin manner.
|
||
- `random`: Randomly selects a host for each DNS update.
|
||
- `disabled` (default): Uses the first host in the list as the primary, only moving to the next host if a failure occurs.
|
||
|
||
### Example Configuration
|
||
|
||
```shell
|
||
external-dns \
|
||
--provider=rfc2136 \
|
||
--rfc2136-host="dns-host-1.yourdomain.com" \
|
||
--rfc2136-host="dns-host-2.yourdomain.com" \
|
||
--rfc2136-host="dns-host-3.yourdomain.com" \
|
||
--rfc2136-load-balancing-strategy="round-robin" \
|
||
--rfc2136-port=53 \
|
||
--rfc2136-zone=example.com \
|
||
--rfc2136-tsig-secret-alg=hmac-sha256 \
|
||
--rfc2136-tsig-keyname=example-key \
|
||
--rfc2136-tsig-secret=example-secret \
|
||
--rfc2136-insecure
|
||
```
|
||
|
||
### Helm
|
||
|
||
```yaml
|
||
extraArgs:
|
||
- --rfc2136-host="dns-host-1.yourdomain.com"
|
||
- --rfc2136-port=53
|
||
- --rfc2136-zone=example.com
|
||
- --rfc2136-tsig-secret-alg=hmac-sha256
|
||
- --rfc2136-tsig-axfr
|
||
|
||
env:
|
||
- name: "EXTERNAL_DNS_RFC2136_TSIG_SECRET"
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: rfc2136-keys
|
||
key: rfc2136-tsig-secret
|
||
- name: "EXTERNAL_DNS_RFC2136_TSIG_KEYNAME"
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: rfc2136-keys
|
||
key: rfc2136-tsig-keyname
|
||
```
|
||
|
||
#### Secret creation
|
||
|
||
```shell
|
||
kubectl create secret generic rfc2136-keys --from-literal=rfc2136-tsig-secret='xxx' --from-literal=rfc2136-tsig-keyname='k8s-external-dns-key' -n external-dns
|
||
```
|
||
|
||
### Benefits
|
||
|
||
- Distributes the load of DNS updates across multiple data centers, preventing any single DC from becoming a bottleneck.
|
||
- Provides flexibility to choose different load balancing strategies based on the environment and requirements.
|
||
- Improves the resilience and reliability of DNS updates by introducing a retry mechanism with a list of hosts.
|