Skip to content

Latest commit

 

History

History
181 lines (134 loc) · 7.31 KB

README.md

File metadata and controls

181 lines (134 loc) · 7.31 KB

coredns traefik plugin

Name

traefik - returns CNAMEs for hosts registered in Traefik instances

Description

Extracts FQDN's from the Host() and HostSNI() values in traefik's http router rules (Traefik's /api/http/routers endpoint). Returns a CNAME result with the traefik instance's domain.

Why?

Homelab + free time. Prior to using traefik, I had a few nginx containers running in different vlans in my homelab. I would create config files by hand, setup static DNS entries, generate certs, and reverse proxy to docker containers by hand.

Traefik took care of a lot of that for me, but I still needed to setup the static DNS entries. Basically I would have a single IP for traefik and a bunch of CNAMEs to it for the various containerized services. Rather than go into pfSense to do this every time, I figured I'd find something more automatic. So I spun up CoreDNS and threw this plugin together to poll the Traefik API periodically and figure out what host names I have http routers referring to. For each of those, I can respond with a CNAME to the Traefik server on-the-fly.

When you pair this with Traefik's ability to configure routes and services via Docker labels, this completely automates the DNS, TLS, and reverse proxy pain when spinning up new containers. It's a nice stopgap until I get around to making the switch to kubernetes & should play nicely during the transition period.

Compilation

This package will always be compiled as part of CoreDNS and not in a standalone way. It will require you to use go get or as a dependency on plugin.cfg.

The manual will have more information about how to configure and extend the server with external plugins.

A simple way to consume this plugin, is by adding the following on plugin.cfg, and recompile it as detailed on coredns.io.

traefik:github.com/scottt732/coredns-traefik

Put this early in the plugin list, so that traefik is executed before any of the other plugins.

After this you can compile coredns by:

go generate
go build

Or you can instead use make:

make

Settings

traefik https://your-traefik.homelab.net/api {
  cname your-traefik.homelab.net
  a 10.0.0.2
  refreshinterval 30
  ttl 30
  insecureskipverify [true|false*]
  resolveapihost [true|false*]
}
  • https://your-traefik.homelab.net/api - This is the endpoint that your Traefik API is listening on. You may need to configure Traefik to expose this.
  • Either (but not both):
    • cname - The host name to return for HTTP routes defined in Traefik. Typically, this is the same host name as in the API URI above.
    • a - The IP address to return for HTTP routes defined in Traefik. Typically, this is the IP address of the Traefik server.
  • refreshinterval - How frequently to poll for changes in Traefik
  • ttl - How long should the results be persisted in downstream DNS caches
  • insecureskipverify - Optional. if your Traefik API endpoint requires HTTPS but you don't have a valid/trusted certificate
  • resolveapihost - Optional. When true and you've chosen a above, this will cause the plugin to resolve your-traefik.homelab.net itself to the IP address specified in the a block
  • fallthrough - Optional

Syntax

Option 1: Returning CNAMEs

traefik https://your-traefik.homelab.net/api {
  cname your-traefik.homelab.net
  refreshinterval 30
  ttl 30
}
  • https://your-traefik.homelab.net/api refers to the base Traefik API endpoint (without trailing slash). Given the base URL, this will hit https://your-traefik.homelab.net/api/http/routers endpoint.
  • cname is the fully qualified domain name (with or without trailing .) that matching requests will have returned. Usually this will be the host name of the API endpoint above.
  • refreshinterval specifies how frequently that api/http/routers endpoint is polled for changes (in seconds)
  • ttl determines that time-to-live for successful responses (in seconds).

Option 2: Returning A records

traefik https://your-traefik.homelab.net/api {
  a 10.0.0.2
  refreshinterval 30
  ttl 30
}
  • a indicates the IP address(es) of your-traefik.homelab.net. This IP address will be returned as A records for all HTTP Routers discovered in Traefik.
  • You can optionally specify a resolveapihost [true|false] (optional, default=false) to have this plugin return A 10.0.0.2 for your-traefik.homelab.net lookups

Example

Imagine you have services in your homelab which you'd like to expose internally/externally as homelab.net subdomains.

  • Traefik is listening on 80/443 on a host whose IP is 10.10.10.2
  • The primary gateway/DNS is on 10.10.10.1
  • You want traefik.homelab.net to route to Traefik's dashboard/API.
  • You want a container named gitea to be resolvable as mytestservice.homelab.net with Traefik taking care of TLS/acme and reverse proxying.

Given this CoreDNS corefile fragment:

homelab.net:53 {
    hosts {
        10.10.10.2 traefik.homelab.net
        fallthrough
    }
    traefik https://traefik.homelab.net/api {
        cname traefik.homelab.net
        refreshinterval 30
        ttl 5
    }
    forward . dns://10.10.10.1
}

This will cause requests for traefik.homelab.net to return the A record 10.10.0.2.

Then we can use a compose.yml like this.

...
services:
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gitea-web.rule=Host(`gitea.homelab.net`)"
      - "traefik.http.routers.gitea-web.service=gitea-web-svc"
      - "traefik.http.routers.gitea-web.entrypoints=websecure"
      - "traefik.http.routers.gitea-web.tls=true"
      - "traefik.http.routers.gitea-web.tls.domains[0].main=homelab.net"
      - "traefik.http.routers.gitea-web.tls.domains[0].sans=*.homelab.net"
      - "traefik.http.services.gitea-web-svc.loadbalancer.server.scheme=http"
      - "traefik.http.services.gitea-web-svc.loadbalancer.server.port=3000"
    ...

The container labels cause Traefik's routers & services to get wired together, waiting for a match on gitea.homelab.net.

This plugin polls the Traefik API and discovers gitea.homelab.net. It dynamically returns a CNAME to traefik.homelab.net, which gets resolved via the A record to 10.10.10.2. Traefik receives the request and sees the host name matches its rule.

In my case, pfSense's DNS Resolver handles DNS for my network and I setup a conditional forwarder for the zone homelab.net to point just those requests to the CoreDNS instance. Alternatively, you can send all of your DNS requests through CoreDNS.

Metrics

If monitoring is enabled (via the prometheus directive) the following metric is exported:

  • coredns_traefik_request_count_total{server} - query count to the traefik plugin.

The server label indicated which server handled the request, see the metrics plugin for details.

Ready

This plugin reports readiness to the ready plugin. It will be ready after the first refresh of data

Also See

See the manual.