1 - Create DNS records from Ingress

Learn how to create DNS records from Ingress

cloudflare-operator can create DNS records from Ingress resources. This guide shows how to configure the controller to automatically create DNS records for your Ingress resources.

Ingress annotations

One of the following annotations is required: cloudflare-operator.io/content or cloudflare-operator.io/ip-ref

Ingress objects that do not have one of these annotations will be ignored by cloudflare-operator.

These are the available annotations:

Annotation Value Description Required
cloudflare-operator.io/content IP address or domain DNS record content (e.g. 69.42.0.69) yes if ip-ref is not set
cloudflare-operator.io/ip-ref Reference to an IP object e.g. my-external-ip yes if content is not set
cloudflare-operator.io/proxied true or false Whether the record should be proxied no
cloudflare-operator.io/ttl 1 or 60 - 86400 TTL of the DNS record no
cloudflare-operator.io/type A, AAAA or CNAME Desired DNS record type no
cloudflare-operator.io/interval e.g. 5m0s Interval at which the DNSRecord object should be reconciled no

An example Ingress resource with annotations:

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cloudflare-operator.io/type: CNAME
    cloudflare-operator.io/content: example.com
  name: blog
  namespace: blog
spec:
  rules:
    - host: blog.example.com
      http:
        paths:
          - backend:
              service:
                name: blog
                port:
                  name: http
            path: /
            pathType: Prefix

This will create a DNS record for the host blog.example.com with the content example.com and the type CNAME.

2 - Monitoring with Prometheus

Monitor cloudflare-operator with Prometheus

Prerequisites

The easiest way to deploy all the necessary components is to use kube-prometheus-stack.

Enable metrics

In order to enable metrics and automatically deploy the required resources, you need to reconfigure the Helm chart.

Create a values.yaml file with the following content:

---
metrics:
  podMonitor:
    enabled: true
  prometheusRule:
    enabled: true

Now you can install / upgrade the Helm chart by following the installation guide.

Install cloudflare-operator Grafana dashboard

# Download Grafana dashboard
wget https://raw.githubusercontent.com/containeroo/cloudflare-operator/master/config/manifests/grafana/dashboards/overview.json -O /tmp/grafana-dashboard-cloudflare-operator.json

# Create the configmap
kubectl create configmap grafana-dashboard-cloudflare-operator --from-file=/tmp/grafana-dashboard-cloudflare-operator.json

# Add label so Grafana can fetch dashboard
kubectl label configmap grafana-dashboard-cloudflare-operator grafana_dashboard="1"

Available metrics

For each cloudflare-operator.io kind, the controller exposes a gauge metric to track the status condition.

Ready status metrics:

cloudflare_operator_account_status
cloudflare_operator_dns_record_status
cloudflare_operator_ip_status
cloudflare_operator_zone_status

Alerting

The following alerting rule can be used to monitor DNS record failures:

groups:
  - alert: DNSRecordFailures
    annotations:
      summary:
        DNSRecord {{ $labels.name }} ({{ $labels.record_name }}) in namespace
        {{ $labels.exported_namespace }} failed
    expr: cloudflare_operator_dns_record_status > 0
    for: 1m
    labels:
      severity: critical

3 - Dynamic DNS with IP objects

Implement dynamic DNS with cloudflare-operator

As described in the core concept, IP objects allow you to use cloudflare-operator as a dynamic DNS controller.

In this guide, we will configure an IP object to fetch the public IP address from the internet and use it as the target content for a DNS record.

Simple example

Create an IP object with the following content:

---
apiVersion: cloudflare-operator.io/v1
kind: IP
metadata:
  name: external-v4
spec:
  ipSources:
    - requestMethod: GET
      url: https://ifconfig.me/ip
    - requestMethod: GET
      url: https://ipecho.net/plain
    - requestMethod: GET
      url: https://myip.is/ip/
    - requestMethod: GET
      url: https://checkip.amazonaws.com
    - requestMethod: GET
      url: https://api.ipify.org
  type: dynamic
  interval: 5m0s

The IP object will fetch the public IP address from the internet using one of the specified URLs.
If the request fails, the next URL will be tried. If all URLs fail, the last known IP will be used and the ready condition will be set to false.

Now, create a DNS record object with the following content:

---
apiVersion: cloudflare-operator.io/v1
kind: DNSRecord
metadata:
  name: example-com
  namespace: cloudflare-operator
spec:
  name: example.com
  ipRef:
    name: external-v4 # reference to the IP object
  proxied: true
  ttl: 1
  type: A

Response filtering

Using jq

You can use jq to filter the response content.

Here is an example for ipify.org:

Request content:

$ curl 'https://api.ipify.org?format=json'
{"ip":"69.42.0.69"}

The IP object would look like this:

---
apiVersion: cloudflare-operator.io/v1
kind: IP
metadata:
  name: external-v4
spec:
  ipSources:
    - requestMethod: GET
      url: https://api.ipify.org?format=json
      responseJQFilter: .ip
  type: dynamic
  interval: 5m0s

Using regex

If you want to use a regex, you can use the postProcessingRegex field.

This might be useful if you want to extract the IP address from a HTML page.

Here is an example for ifconfig.me:

Request content:

$ curl 'https://ifconfig.me/'
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
...

In this case, the IP object would look like this:

---
apiVersion: cloudflare-operator.io/v1
kind: IP
metadata:
  name: external-v4
spec:
  ipSources:
    - requestMethod: GET
      url: https://ifconfig.me/
      postProcessingRegex: '(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
  type: dynamic
  interval: 5m0s

Fetching IP from an API

If you want to fetch the IP address from an API, you can use the responseJQFilter field.

In this example, we are going to fetch the IP from a Hetzner cloud instance.
To authenticate with the API, you can configure the IP object to use a secret where the secret key will be used as the header name and the secret value will be used as the header value.

Create a secret with the following content:

---
apiVersion: v1
kind: Secret
metadata:
  name: hetzner-cloud-api-key
  namespace: cloudflare-operator
stringData:
  Authorization: Bearer <your-api-token>

Now, create an IP object with the following content:

---
apiVersion: cloudflare-operator.io/v1
kind: IP
metadata:
  name: my-instance-v4
spec:
  ipSources:
    - requestHeaders:
        Accept: application/json
      requestHeadersSecretRef:
        name: hetzner-cloud-api-key
        namespace: cloudflare-operator
      requestMethod: GET
      responseJQFilter: .servers[] | select(.name == "my-instance.example.com").public_net.ipv4.ip
      url: https://api.hetzner.cloud/v1/servers
  type: dynamic
  interval: 5m0s

4 - Fetch IP from a Kubernetes object

Learn how to use cloudflare-operator to fetch an IP address from a Kubernetes object

If you have a Kubernetes object that contains an IP address, you can use cloudflare-operator to fetch the IP address from the object and use it as the target content for a DNS record.

This can be useful if you are using Istio or want to fetch the IP from a Kubernetes service.

This guide will show you how to configure an IP object to fetch the IP address from a Kubernetes service.

Operator configuration

Add a kubectl sidecar to the operator pod by using the following Helm values:

sidecars:
  - name: proxy
    image: bitnami/kubectl
    args: ["proxy", "--port=8858"]

The operator will need additional permissions to access services.

In order to grant the operator these permissions, add the following Helm values:

clusterRole:
  extraRules:
    - apiGroups:
        - ""
      resources:
        - services
      verbs:
        - get
        - list

Install or update the Helm chart using this guide.

IP object

An IP object could then look like this:

---
apiVersion: cloudflare-operator.io/v1
kind: IP
metadata:
  name: ingress-ip
spec:
  type: dynamic
  ipSources:
    - url: localhost:8858/api/v1/namespaces/ingress-nginx/services/ingress-nginx
      responseJQFilter: ".status.loadBalancer.ingress[0].ip"

This IP object will fetch the IP address from the Kubernetes service ingress-nginx in the namespace ingress-nginx using the kubectl proxy.