readme.md
Rama main · réplica de lectura del repositorio original.
# AdguardHome provider for ExternalDNS
A [webhook plugin](https://github.com/kubernetes-sigs/external-dns/blob/v0.18.0/docs/tutorials/webhook-provider.md) for [ExternalDNS](https://github.com/kubernetes-sigs/external-dns) to support AdguardHome DNS provider.
This provider implementation is based on using AdguardHome [filtering rules](https://adguard-dns.io/kb/general/dns-filtering-syntax/).
It takes ownership only for rules which are created by this provider, so existing rules are not touched.
### Compatibility
This plugin was tested with AdguardHome up to v0.107.79 and ExternalDNS v0.24.0.
The provider uses the ExternalDNS v0.24.0 webhook library and requires Go 1.27.0 or later to build.
The webhook server listens on `:8888` with 10-second read and write timeouts and a default 32 MiB request body limit.
Oversized requests return HTTP 413.
Pass `--max-body-size` to the provider to override the limit in bytes, for example `--max-body-size=67108864` for 64 MiB.
Values of `0` or less disable the limit; prefer a finite limit to bound memory use.
Before accepting webhook requests, the provider checks AdGuard and migrates
managed rules when needed. Startup failures leave the webhook unavailable.
SIGINT and SIGTERM cancel in-flight AdGuard HTTP calls and stop the process.
## Experimental DNS rewrite rules
Set `ADGUARD_HOME_USE_DNSREWRITE=true` on the provider container to test explicit
[`$dnsrewrite` rules](https://adguard-dns.io/kb/general/dns-filtering-syntax/#dnsrewrite-modifier).
The default is `false`; an unset or empty value also disables the flag. Invalid boolean values fail startup.
Restart the provider after changing the flag.
When enabled, the provider migrates its existing managed A and TXT records at
startup, including when ExternalDNS has no DNS changes to apply. New records also
use this syntax. Managed allow-rule companions are removed. Labels and rules
belonging to other owners remain unchanged. TXT values, including ExternalDNS TXT
registry ownership records, become queryable over DNS.
Migration does not write anything in provider dry-run mode.
Wildcard hostnames are rejected in rewrite mode; exclude them before enabling
it. Rejection prevents startup migration or the entire change batch from being saved.
For example, a managed record becomes two adjacent lines:
```text
! 192.0.2.10 app.example.com #$managed by external-dns
|app.example.com|$dnsrewrite=NOERROR;A;192.0.2.10
```
Keep each ownership comment adjacent to its rule; missing or mismatched pairs stop
reconciliation. Rules match only the exact non-wildcard hostname. Multiple
addresses produce one pair per address. TXT pairs preserve the original value
and labels in a JSON comment:
```text
! $managed by external-dns {"dnsName":"txt.example.com","targets":["verification-token"],"recordType":"TXT"}
|txt.example.com|$dnstype=TXT,dnsrewrite=NOERROR;TXT;verification-token
```
TXT targets can be plain text or a single DNS-quoted string, with at most 255
decoded bytes per target. Reserved characters are escaped automatically; original
values and labels are preserved for rollback. Multiple targets produce separate
TXT records. Invalid quoting, multi-string quoted targets, oversized values, and
literal line breaks reject the entire batch without saving rules. During startup,
one invalid existing TXT target prevents migration and the webhook from starting.
A and TXT records can share a hostname. TXT-only rewrites do not suppress upstream
A, AAAA, or other record types.
AdGuard Home classifies these answers as **Rewritten**, not Blocked, so they do
not inflate blocked-query statistics. This requires AdGuard Home v0.105.0 or later.
An A-only rewrite returns an empty `NOERROR` answer for other query types unless
another applicable rewrite supplies that type. Provider management markers and
labels stay in comments; only endpoint TXT values are served. With the flag off,
TXT values remain comments and are not served over DNS.
To roll back, set the flag to `false` or remove it, then restart this build of the
provider. Startup converts managed A rewrite pairs back to hosts-style rules,
restores their allow-rule companions, and converts TXT pairs back to comments.
Roll back before switching to an older provider build, which cannot read the new
metadata pairs. Older builds also misparse TXT values containing whitespace, even
after rollback. Remove those TXT endpoints from desired state and reconcile before
downgrading, or keep this build with the flag disabled.
## Setting up ExternalDNS for AdguardHome
This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster using AdguardHome.
### Deploy ExternalDNS
Connect your `kubectl` client to the cluster you want to test ExternalDNS with.
Then apply one of the following manifests file to deploy ExternalDNS.
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods","nodes"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [ "discovery.k8s.io" ]
resources: [ "endpointslices" ]
verbs: [ "get","watch","list" ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
spec:
replicas: 1
selector:
matchLabels:
app: external-dns
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.k8s.io/external-dns/external-dns:v0.18.0
args:
- --source=service # ingress is also possible
- --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above.
- --provider=webhook
- --webhook-provider-url=http://localhost:8888
- name: adguardhome-provider
image: ghcr.io/zekker6/external-dns-provider-adguard:v1.5.2
env:
- name: ADGUARD_HOME_URL
value: "YOUR_ADGUARD_HOME_URL" # Note: URL should be in the format of http://adguard.home:3000/control/
- name: ADGUARD_HOME_PASS
value: "YOUR_ADGUARD_HOME_PASSWORD"
- name: ADGUARD_HOME_USER
value: "YOUR_ADGUARD_HOME_USER"
# It is possible to run multiple instances of provider with a single AdguardHome instance by using different owner refs
# - name: ADGUARD_HOME_MANAGED_BY_REF
# value: "cluster-name"
```
### Deploy ExternalDNS with the Helm chart
ExternalDNS project provides an [official Helm chart](https://github.com/kubernetes-sigs/external-dns/tree/master/charts/external-dns) that can be used to deploy ExternalDNS with AdguardHome provider.
Example values file for the Helm chart:
```yaml
sources:
- ingress
- service
provider:
name: webhook
webhook:
image:
repository: ghcr.io/zekker6/external-dns-provider-adguard
tag: v1.5.2
pullPolicy: IfNotPresent
env:
- name: ADGUARD_HOME_URL
valueFrom:
secretKeyRef:
name: adguard-credentials
key: ADGUARD_HOME_URL
- name: ADGUARD_HOME_USER
valueFrom:
secretKeyRef:
name: adguard-credentials
key: ADGUARD_HOME_USER
- name: ADGUARD_HOME_PASS
valueFrom:
secretKeyRef:
name: adguard-credentials
key: ADGUARD_HOME_PASS
securityContext:
runAsUser: 0
runAsNonRoot: false
allowPrivilegeEscalation: true
livenessProbe:
httpGet:
path: /healthz
port: 8888
readinessProbe:
httpGet:
path: /healthz
port: 8888
service:
port: 8888
domainFilters:
- example.com
extraArgs:
- --webhook-provider-url=http://localhost:8888
serviceAccount:
create: true
name: external-dns
rbac:
create: true
additionalPermissions: []
logLevel: info
logFormat: text
```
## Deploying an Nginx Service
Create a service file called 'nginx.yaml' with the following contents:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
annotations:
external-dns.alpha.kubernetes.io/hostname: my-app.example.com
spec:
selector:
app: nginx
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 80
```
ExternalDNS uses `external-dns.alpha.kubernetes.io/hostname` annotation to determine what services should be registered with DNS. Removing the annotation will cause ExternalDNS to remove the corresponding DNS records.
Create the deployment and service:
```console
kubectl create -f nginx.yaml
```
Depending where you run your service it can take a little while for your cloud provider to create an external IP for the service.
Once the service has an external IP assigned, ExternalDNS will notice the new service IP address and synchronize the AdguardHome DNS records.
## Verifying AdguardHome DNS records
Check your AdguardHome DNS records to see if the new record was created.
Click on "Filters" and then "Custom filtering rules"
This should show the external IP address of the service as the "Answer" for your domain.
## Cleanup
Now that we have verified that ExternalDNS will automatically manage AdguardHome DNS records, we can delete the tutorial's example:
```
kubectl delete service -f nginx.yaml
kubectl delete service -f externaldns.yaml
```