Skip to content

About

ExternalDNS webhook to manage DNScaster DNS Records.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

ExternalDNS Webhook Provider for DNScaster

ExternalDNS is a Kubernetes add-on for automatically managing DNS records for Kubernetes ingresses and services by using different DNS providers. This webhook provider allows you to automate DNS records from your Kubernetes clusters to your DNScaster service provider.

Requirements

  • ExternalDNS >= v0.15.0

Note

v0.15.0 of ExternalDNS added support for providerSpecific annotations in Ingress/Service objects for webhook providers.

While older versions of ExternalDNS may work, support for this feature will not be present.

Limitations

  • Targeting multiple Nameserver Set is not supported. A single NameserverSet ID must be given through an ENV var at runtime.

  • IP Monitors are only supported for A/AAAA records.

How Changes Are Applied

ExternalDNS sends the webhook batches of records to create, update and delete. They are applied in this order: deletions, then updates, then creations.

A DNScaster host holds a single target, so a record with several targets, such as a Service with more than one load balancer IP, is kept as one host per target, all sharing the record's name. Each host gets its own monitor, so DNScaster hides the targets that go offline and keeps answering with the others. The webhook reports these hosts to external-dns as a single record.

  • A deleted record removes its hosts, then the monitors they used.
  • An updated record changes its hosts in place with PUT: data, TTL and properties are sent, and their monitors are updated the same way, so hosts and monitors keep their IDs. A host whose target is kept is only updated when its TTL or properties change. A host whose target was dropped takes over one of the new targets, or is deleted when none is left. New targets left over get new hosts. A host gaining a monitor annotation gets a new monitor. A host losing it is deleted and created again, as the update cannot detach the monitor from the host, and a monitor in use cannot be deleted.
  • A created record gets a monitor first, then a host, for each target.

Properties are replaced as a whole on every update, so labels removed from the annotations are removed from the hosts and their monitors too.

Configuration Options

DNScaster Connection Configuration

Environment Variable Description Default Value
DNSCASTER_OWNER_ID ID used when filtering resources to save on API requests N/A
DNSCASTER_API_KEY API key needed to communicate with DNScaster API N/A
DNSCASTER_NAMESERVER_SET_ID DNScaster Nameserver Set tied to this provider N/A
DNSCASTER_SKIP_TLS_VERIFY Whether to skip TLS verification (true or false). false
DNSCASTER_DRY_RUN Log DNScaster writes instead of sending them. false

Note

external-dns does not forward its --dry-run flag to webhook providers, so set DNSCASTER_DRY_RUN on the webhook container instead. Reads still reach the DNScaster API. Since nothing is applied, external-dns sends the same changes on every sync, and each one also lists zones and hosts again, which counts against the API rate limit.

Default Values Configuration

Environment Variable Description Default Value
DNSCASTER_DEFAULT_TTL Default TTL value to be set for DNS records with no specified TTL. 300
DNSCASTER_DEFAULT_PAGE_SIZE Records requested per page when listing (max_results). 100

Server Configuration

Environment Variable Description Default Value
SERVER_HOST The host address where the server listens. localhost
SERVER_PORT The port where the server listens. 8888
SERVER_READ_TIMEOUT Duration the server waits before timing out on read operations. 0s
SERVER_WRITE_TIMEOUT Time to answer a webhook request before returning a 5xx. 0s
DOMAIN_FILTER List of domains to include in the filter. Empty
EXCLUDE_DOMAIN_FILTER List of domains to exclude from filtering. Empty
REGEXP_DOMAIN_FILTER Regular expression for filtering domains. Empty
REGEXP_DOMAIN_FILTER_EXCLUSION Regular expression for excluding domains from the filter. Empty

Note

A timeout of 0s means no timeout. external-dns gives up on a webhook request after --webhook-provider-read-timeout plus --webhook-provider-write-timeout (15s by default) and exits. Set SERVER_WRITE_TIMEOUT a few seconds below that sum (e.g. 12s) so the webhook answers with a 5xx first, which external-dns retries on its next sync.

Logging Configuration

Environment Variable Description Default Value
LOG_LEVEL Change the verbosity of logs (debug, info, warn or error) info
LOG_FORMAT The format in which logs will be printed. (text or json) text

Provider Specific Annotations

All provider annotations are prefixed with: external-dns.kubernetes.io/webhook-dnscaster-

Provider annotations are implemented using the properties field on DNScaster's API. As such, the provider annotations have the same limitations. More info can be found in DNScaster's docs.

IP Monitor Annotations

Monitors are created from provider specific annotations. This provider currently supports the following annotations:

Annotation Description Default
ip-monitor-uri URI for IP monitor N/A
ip-monitor-hostname Hostname for IP monitor Record's FQDN
ip-monitor-treat_redirects How Monitor will treat redirects online

Example:

IP monitors can be used to provide monitoring for your endpoint. Since LoadBalancer IPs are usually not known ahead of time, defining a uri without a host is perfectly valid and the provider will grab the target from the record.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-route # Let's assume this route is backed by a LB IP at 1.1.1.1
  annotations:
    external-dns.kubernetes.io/webhook-dnscaster-ip-monitor-uri: "ping"

This would create an IP Monitor with the following URI: ping://1.1.1.1


If your IP Monitor URI is based on HTTP/HTTPS, the hostname will also get populated from the underlying resource. Note that again, the IP does not need to be known ahead of time.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-route # Let's assume this route is backed by a LB IP at 1.1.1.1
  annotations:
    external-dns.kubernetes.io/webhook-dnscaster-ip-monitor-uri: "https:/health" # URI parsing is using Go's net/url package

    # Note that this URI would result in the same output
    external-dns.kubernetes.io/webhook-dnscaster-ip-monitor-uri: "https:///health"

This would create an IP Monitor with the following URI: https://1.1.1.1/health


A port can be given without a host, and an IPv6 target is bracketed as DNScaster expects:

ip-monitor-uri Target Monitor URI
tcp://:9876 1.1.1.1 tcp://1.1.1.1:9876
ping 2001:db8::1 ping://[2001:db8::1]
https:///health 2001:db8::1 https://[2001:db8::1]/health

Of course, it is also possible to directly give a full URI if the IP you wish to monitor is known ahead of time. This can be useful when the monitor should target a different IP from the managed endpoint.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-route # Let's assume this route is backed by a LB IP at 1.1.1.1
  annotations:
    external-dns.kubernetes.io/webhook-dnscaster-ip-monitor-uri: "ping://1.2.3.4"

This would create an IP Monitor with the following URI: ping://1.2.3.4. A record with several targets still gets one monitor per host, so each of them would watch 1.2.3.4.


It is also possible to use a different URI for HTTP/HTTPS monitors. Do not forget to set the hostname through an annotation, otherwise the endpoint's FQDN will be used instead:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-route # Let's assume this route is backed by a LB IP at 1.1.1.1
  annotations:
    external-dns.kubernetes.io/webhook-dnscaster-ip-monitor-uri: "https://1.2.3.4/health"
    external-dns.kubernetes.io/webhook-dnscaster-ip-monitor-hostname: "api.other.com"
spec:
  hostnames:
    - "api.example.com"

Label Annotations

It is possible to set arbitrary labels on Hosts/Monitors using a provider specific annotation. The labels are set with an annotation prefixed with: external-dns.kubernetes.io/webhook-dnscaster-label-

For example, if we want to set these labels:

Label Value
network ethereum
service token-api

The annotation syntax will be:

external-dns.kubernetes.io/webhook-dnscaster-label-network: ethereum
external-dns.kubernetes.io/webhook-dnscaster-label-service: token-api

Note that since labels are arbitrary and can be anything, the label prefix will be trimmed on the resulting property. This allows you to not worry about the length of the label prefix in your implementation.

i.e.: The resulting properties for these labels on a host would be:

{
  "properties": {
    "network": "ethereum",
    "service": "token-api"
  }
}

Labels with the format prefix/label: value require an escape sequence for the / character. The escape sequence for / is ~1. As such, an annotation for the label registry/name: mainnet would be written as:

external-dns.kubernetes.io/webhook-dnscaster-label-registry~1name: mainnet

Similarly, the ~ character also needs an escape sequence. The special replacement character ~0 is used to replace ~ in label name.

Local Development

make dev creates a kind cluster with a local image registry and starts Tilt against it. Tilt installs cilium, kube-prometheus-stack, external-dns with the webhook built from this checkout, the dnscaster-exporter and the manifests in example/. Changes under cmd/, pkg/ and internal/ are rebuilt and synced into the running webhook.

It needs docker and the tools from the nix dev shell (kind, tilt, helm, kubectl, sops). The DNScaster API key is decrypted with sops, so you also need the age key listed in .sops.yaml.

make dev       # create the cluster if needed, then start Tilt
make dev-down  # remove the example records from DNScaster, then delete the cluster

Warning

The test env uses the real DNScaster API and creates records under dnstest.pinax.network. Its calls count against the same rate limit as every other cluster. Exiting Tilt leaves external-dns running, so run make dev-down when you are done. Deleting the cluster directly leaves the example records in DNScaster.

About

ExternalDNS webhook to manage DNScaster DNS Records.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages