Use External-DNS with FluxCD to automate DNS management for Kubernetes deployments, integrated with Cloudflare as the DNS provider
Managing DNS records can invole a lot of manual work. If you’ve ever had to manually copy and paste IP addresses to create DNS records, or tried to rely on wildcard entries that point to a single load balancer IP or CNAME, you know the pain. It often goes something like this: you run kubectl to grab the load balancer IP, then hop over to your Terraform DNS repo, make the necessary changes, create a Merge Request, wait for the review, and only after all that, you finally get the DNS record updated. It’s a workflow that’s slow, prone to mistakes, and just doesn’t scale well.
That’s where External-DNS makes a difference. It automates the entire DNS management process, updating records automatically as services change within your Kubernetes cluster. No more manual updates, no more waiting for approvals—just up-to-date DNS records in real-time.
In this post, I’ll walk you through you how to deploy External-DNS with FluxCD, using Cloudflare as the DNS provider.
External-DNS automatically manages DNS records based on the resources defined in your Kubernetes cluster. As services are created or removed, External-DNS ensures that DNS entries are updated to reflect the current state of your applications. This automation saves time, reduces the potential for misconfigurations, and provides dynamic scaling for environments that frequently change.
In our setup, we’ll be using FluxCD to manage the deployment of External-DNS as part of our GitOps workflow, ensuring that all configurations and changes are version-controlled and declarative.
Let’s dive into the specifics of how to configure External-DNS with FluxCD and Cloudflare as the DNS provider. Below, we outline the necessary Kubernetes resources and configurations required to make it all work.
We’ll start by setting up a specific namespace for External-DNS. Here all the External-DNS resources will be deployed and managed.
apiVersion: v1
kind: Namespace
metadata:
name: external-dns
labels: {}
External-DNS provides us with a convienient Helm Chart that we can use to rollout in our cluster. We utilize FluxCD to deploy it, so we define the HelmRepository for External-DNS to make it accessible for FluxCD.
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: external-dns
namespace: external-dns
spec:
interval: 160m
url: https://kubernetes-sigs.github.io/external-dns/
This specifies where to pull the chart from and how often to check for updates (in this case, every 160 minutes).
Next, we configure the HelmRelease for External-DNS, which tells FluxCD to install and manage the External-DNS chart. We’ll also configure it to use Cloudflare as the DNS provider.
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: external-dns
namespace: external-dns
spec:
chart:
spec:
chart: external-dns
sourceRef:
kind: HelmRepository
name: external-dns
namespace: external-dns
version: 1.14.5
interval: 1h
releaseName: external-dns
values:
provider:
name: cloudflare
env:
- name: CF_API_TOKEN
valueFrom:
secretKeyRef:
name: cloudflare-api-token
key: apiToken
affinity:
nodeAffinity:
# prefer scheduling on control-plane machines
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
topologyKey: kubernetes.io/hostname
nodeSelector:
kubernetes.io/os: linux
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
In our setup, we use Cloudflare as the DNS provider
for External-DNS. To allow External-DNS to authenticate with Cloudflare, we reference the Cloudflare API token from a Kubernetes secret, which stores the token and makes it accessible for the External-DNS deployment.
We provide any additional settings that the External-DNS helm chart supports. In this case, the example comes from a set-up were we deploy controllers on Control Plane machines within an Kubernetes cluster.
To allow External-DNS to manage DNS records in Cloudflare, you’ll need to create an API token that grants the necessary permissions. The API token will be securely stored as a Kubernetes secret, enabling External-DNS to authenticate with Cloudflare and update DNS records automatically as services change in your Kubernetes cluster.
To create a token, follow these steps:
With the token created, we now need to store it as a Kubernetes secret so that External-DNS can use it for authentication. Here’s the command to create the secret, replacing YOUR_CLOUD_FLARE_API_TOKEN
with the actual token you generated:
kubectl create secret generic -n external-dns cloudflare-api-token --from-literal=apiToken=YOUR_CLOUD_FLARE_API_TOKEN --dry-run=client -o yaml
This command generates the secret containing the API token, which External-DNS will use to authenticate with Cloudflare.
Once everything is set up, External-DNS watches for changes to Kubernetes resources like services or ingresses. When a new service is created with an external IP, External-DNS automatically creates a corresponding DNS entry in Cloudflare, associating the IP with the correct domain name. As applications scale or change, External-DNS ensures that these DNS records are always accurate and up to date. It also handles cleanup, removing DNS entries when services are deleted, so there are no stale records left behind.
External DNS with Cloudflare overview
A key part of how External-DNS manages these DNS records is through the use of TXT records. These TXT records are automatically created alongside the A or CNAME records for your services and play a crucial role in maintaining and tracking DNS entries.
TXT records serve as a way for External-DNS to “tag” the DNS entries it manages. Each time External-DNS creates or modifies a DNS record in Cloudflare, it also generates a corresponding TXT record. This TXT record contains metadata that links the DNS entry to the Kubernetes resource that owns it. This tagging system is important for several reasons:
TXT records may contain sensitive information, such as the internal ingress name or namespace, which attackers could potentially exploit to gather details about your infrastructure. To protect this information from unauthorized access, you can enable encryption of TXT records using External-DNS. Encryption is enabled by setting the –txt-encrypt-enabled flag. Additionally, you must provide a 32-byte encryption key in URL-safe base64 form using the –txt-encrypt-aes-key flag.
To generate the encryption key, you can use the following command:
openssl rand -base64 16 | tr -- '+/' '-_'
We can use this to create a secret in our Kubernetes cluster and configure it in the HelmRelease
.
kubectl create secret generic external-dns-txt-encryption-key \
--from-literal=ENCRYPTION_KEY=$(openssl rand -hex 16) \
--namespace external-dns
Next, we can add the extra environment variable to the HelmRelease:
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: external-dns-txt-encryption-key
key: ENCRYPTION_KEY
As well as the arguments that enable the encrypted txt feature:
extraArgs:
- --txt-encrypt-enabled
- --txt-encrypt-aes-key=$(ENCRYPTION_KEY)
When working with multiple environments (e.g., development, staging, and production), it’s important to differentiate the DNS records managed by each environment. This can be done by customizing the controller name in External-DNS. You can use the –txt-owner-id flag to assign a unique identifier for each environment, such as prod-external-dns or dev-external-dns. This ensures that each External-DNS instance manages only the records for its environment, preventing conflicts and ensuring the right records are cleaned up or modified in the correct environment. You can do this by configuring txtOwnerId: prd
in the HelmRelease.
One of the key advantages of using FluxCD with External-DNS is the automatic deployment and management of External-DNS itself. Instead of manually setting up and configuring External-DNS each time you spin up a new environment, FluxCD ensures that everything is deployed and configured for you.
Whether you’re tweaking the provider settings or rolling out updates, FluxCD handles the deployment seamlessly, ensuring External-DNS is always up and running without you having to lift a finger. This level of automation simplifies operations and guarantees that your DNS management tool is always in sync with the rest of your infrastructure.
1. No more manually copy pasting IP addresses
Another significant benefit is the hands-off approach to managing DNS records. If you’ve ever had to manually copy and paste IP addresses into a DNS provider or run Terraform scripts to update DNS entries, you’ll appreciate how much time and effort External-DNS saves. It automatically updates your DNS provider (in this case, Cloudflare) whenever a service is created or modified in Kubernetes. No more logging into your DNS provider’s dashboard or running scripts—everything is handled in real-time by External-DNS. This not only reduces manual work but also ensures that your DNS records are always accurate and up-to-date with your cluster’s state.
2. Automate the cleanup
One of the most practical improvements is the way External-DNS handles clean-up. In a fast-moving environment, it’s easy to forget about old DNS records when a service is removed, leaving behind unused entries that clutter your DNS configuration. Over time, this can lead to confusion or even security issues. With External-DNS, this becomes a non-issue. It automatically removes DNS records when services are deleted, so you won’t have to worry about cleaning up stale entries manually. This ensures your DNS records stay tidy and relevant, reducing the risk of issues down the line.
Integrating External-DNS with FluxCD and Cloudflare brings significant value to any Kubernetes-based environment. By automating the deployment and ongoing DNS management, you eliminate the manual overhead of maintaining DNS records, reduce the risk of errors, and ensure that your DNS entries stay in sync with your infrastructure.
With the added benefit of automated clean-up, this setup keeps your DNS configurations clean and hassle-free, allowing you to focus on scaling and improving your applications rather than managing DNS manually.