[PR #236] (feat) DNS Authority #992

Open
opened 2026-04-19 14:26:34 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/fosrl/newt/pull/236
Author: @mattv8
Created: 2/17/2026
Status: 🔄 Open

Base: devHead: dns-authority


📝 Commits (7)

  • 0db25c2 DNS authority management and features
  • 0d1c29b Add support for updating TLS certificates in auth proxy
  • 705f4e0 Add multi-target, path routing, and proxy settings to auth config
  • d031126 Add backward compatibility for single target URL in resource auth config
  • ef8755b feat(dns): add sticky session affinity
  • 896abb1 feat(dns): blend intelligent scoring with health latency
  • d9f1ec4 fix(healthcheck): publish status every check for latency telemetry

📊 Changes

8 files changed (+2450 additions, -16 deletions)

View changed files

📝 README.md (+26 -0)
auth/auth.go (+1160 -0)
dns/authority.go (+868 -0)
📝 get-newt.sh (+75 -12)
📝 go.mod (+2 -0)
📝 go.sum (+4 -0)
📝 healthcheck/healthcheck.go (+11 -4)
📝 main.go (+304 -0)

📄 Description

Community Contribution License Agreement

By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.

Description

This adds DNS Authority and Auth Proxy capabilities to Newt. The companion Pangolin PR is https://github.com/fosrl/pangolin/pull/2490. More context is in the discussion.

What this does

DNS Authority (dns/authority.go): An authoritative DNS server built on miekg/dns. Listens on port 53 (UDP + TCP), serves A/NS/SOA records for zones pushed from Pangolin. Supports three routing policies:

  • Failover: returns only the highest-priority healthy target
  • Round-robin: rotates through healthy targets
  • Priority: returns all healthy targets

Zones are held in memory and fully repopulated on each Newt reconnect. Wildcard matching is supported (*.example.com matches any subdomain). If no healthy targets exist, falls back to returning all targets (best effort). The server performs a pre-flight port 53 bind check with clear error messages (systemd-resolved, dnsmasq, etc.) and a self-test query after startup.

Auth Proxy (auth/auth.go): An HTTP reverse proxy that enforces SSO at the edge. Uses a hybrid validation model: first tries local JWT verification using an RSA public key fetched from Pangolin (sub-ms latency), then falls back to calling Pangolin's /auth/session/validate API. Supports per-resource SSO toggle, access blocking, email whitelist, and injects X-Auth-User / X-Auth-User-ID headers for the backend.

WebSocket handlers (in main.go): Handles newt/dns/authority/config and newt/auth/proxy/config messages from Pangolin with actions: start, stop, update, remove. Reports DNS server status back to Pangolin via newt/dns/status.

Configuration

Flag / Env Var Default Description
--dns-bind / DNS_BIND_ADDR 0.0.0.0 Bind address for the DNS server
--disable-dns-authority / DISABLE_DNS_AUTHORITY false Disable the DNS server entirely
NEWT_AUTH_PROXY_BIND :80 Bind address for the auth proxy

Backward compatibility

DNS Authority and Auth Proxy only activate when Pangolin pushes configuration. If Pangolin doesn't have the feature enabled, Newt behaves exactly as before. The --disable-dns-authority flag lets operators explicitly opt out even if the server-side is enabled.

Port 53 notes

Port 53 requires root on Linux. If systemd-resolved is occupying port 53, either disable it (sudo systemctl disable --now systemd-resolved) or bind Newt to a specific IP via --dns-bind.

New dependencies

How to test?

Option 1: Full local test stack

There's a complete end-to-end test stack in mattv8/pangolin-testing. It spins up a PostgreSQL, Pangolin, Gerbil, two Newt instances, two backends, and a test client on a Docker bridge network.

git clone https://github.com/mattv8/pangolin-testing testing
cd testing/
sudo modprobe wireguard
docker compose down -v && docker compose up -d
docker compose ps
bash scripts/bootstrap.sh

Verify:

dig @localhost -p 5353 app.test.dev A +short      # → 172.28.0.10
dig @localhost -p 5354 app.test.dev A +short      # → 172.28.0.10
dig @localhost -p 5353 anything.test.dev A +short  # → 172.28.0.10 (wildcard)

Failover:

docker compose stop backend
dig @localhost -p 5353 app.test.dev A +short       # → secondary IP
docker compose start backend

Auth proxy:

curl -sI http://localhost:8080/ | grep Location    # → 302 redirect to login

See the testing README for the architecture diagram and all available test commands.

Option 2: Drop-in to an existing stack

sudo cp /usr/local/bin/newt /usr/local/bin/newt.official
curl -fsSL https://raw.githubusercontent.com/mattv8/pangolin-testing/main/scripts/get-newt.sh | bash
sudo systemctl restart newt
sudo journalctl -u newt -f   # watch for DNS Authority log lines

Rollback:

sudo cp /usr/local/bin/newt.official /usr/local/bin/newt && sudo systemctl restart newt

You'll also need the companion Pangolin build (see the Pangolin PR) to actually push zone configs.

See it in action

Run this command and watch it rotate between my public IP's (please don't DOS me):

for i in $(seq 1 20); do echo "$(date +%H:%M:%S)  $(dig @ns1.postportal.dev.visnovsky.us +short +time=2 +tries=1 postportal.dev.visnovsky.us A | head -1)"; sleep 0.5; done

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/fosrl/newt/pull/236 **Author:** [@mattv8](https://github.com/mattv8) **Created:** 2/17/2026 **Status:** 🔄 Open **Base:** `dev` ← **Head:** `dns-authority` --- ### 📝 Commits (7) - [`0db25c2`](https://github.com/fosrl/newt/commit/0db25c200af1f816c46a99dbd4b8c111cf38a6bc) DNS authority management and features - [`0d1c29b`](https://github.com/fosrl/newt/commit/0d1c29bebad0b1ea633aa02ae0293ca7c9a95d61) Add support for updating TLS certificates in auth proxy - [`705f4e0`](https://github.com/fosrl/newt/commit/705f4e0f519e3892cf88506d9cb3eae2255ce135) Add multi-target, path routing, and proxy settings to auth config - [`d031126`](https://github.com/fosrl/newt/commit/d03112680bdd83ab2d2ffd46a8db7358839c054b) Add backward compatibility for single target URL in resource auth config - [`ef8755b`](https://github.com/fosrl/newt/commit/ef8755b643f72efb845302525c9a18b7b2667d86) feat(dns): add sticky session affinity - [`896abb1`](https://github.com/fosrl/newt/commit/896abb1ef14f09bcff82f86dda348bb7c0ccc10f) feat(dns): blend intelligent scoring with health latency - [`d9f1ec4`](https://github.com/fosrl/newt/commit/d9f1ec4e036595221ec61b0b4b4e45b87b2d244c) fix(healthcheck): publish status every check for latency telemetry ### 📊 Changes **8 files changed** (+2450 additions, -16 deletions) <details> <summary>View changed files</summary> 📝 `README.md` (+26 -0) ➕ `auth/auth.go` (+1160 -0) ➕ `dns/authority.go` (+868 -0) 📝 `get-newt.sh` (+75 -12) 📝 `go.mod` (+2 -0) 📝 `go.sum` (+4 -0) 📝 `healthcheck/healthcheck.go` (+11 -4) 📝 `main.go` (+304 -0) </details> ### 📄 Description ## Community Contribution License Agreement By creating this pull request, I grant the project maintainers an unlimited, perpetual license to use, modify, and redistribute these contributions under any terms they choose, including both the AGPLv3 and the Fossorial Commercial license terms. I represent that I have the right to grant this license for all contributed content. ## Description This adds DNS Authority and Auth Proxy capabilities to Newt. The companion Pangolin PR is https://github.com/fosrl/pangolin/pull/2490. More context is in [the discussion](https://github.com/orgs/fosrl/discussions/2423). ### What this does **DNS Authority** (`dns/authority.go`): An authoritative DNS server built on [`miekg/dns`](https://github.com/miekg/dns). Listens on port 53 (UDP + TCP), serves A/NS/SOA records for zones pushed from Pangolin. Supports three routing policies: - **Failover:** returns only the highest-priority healthy target - **Round-robin:** rotates through healthy targets - **Priority:** returns all healthy targets Zones are held in memory and fully repopulated on each Newt reconnect. Wildcard matching is supported (`*.example.com` matches any subdomain). If no healthy targets exist, falls back to returning all targets (best effort). The server performs a pre-flight port 53 bind check with clear error messages (systemd-resolved, dnsmasq, etc.) and a self-test query after startup. **Auth Proxy** (`auth/auth.go`): An HTTP reverse proxy that enforces SSO at the edge. Uses a hybrid validation model: first tries local JWT verification using an RSA public key fetched from Pangolin (sub-ms latency), then falls back to calling Pangolin's `/auth/session/validate` API. Supports per-resource SSO toggle, access blocking, email whitelist, and injects `X-Auth-User` / `X-Auth-User-ID` headers for the backend. **WebSocket handlers** (in `main.go`): Handles `newt/dns/authority/config` and `newt/auth/proxy/config` messages from Pangolin with actions: start, stop, update, remove. Reports DNS server status back to Pangolin via `newt/dns/status`. ### Configuration | Flag / Env Var | Default | Description | |---|---|---| | `--dns-bind` / `DNS_BIND_ADDR` | `0.0.0.0` | Bind address for the DNS server | | `--disable-dns-authority` / `DISABLE_DNS_AUTHORITY` | `false` | Disable the DNS server entirely | | `NEWT_AUTH_PROXY_BIND` | `:80` | Bind address for the auth proxy | ### Backward compatibility DNS Authority and Auth Proxy only activate when Pangolin pushes configuration. If Pangolin doesn't have the feature enabled, Newt behaves exactly as before. The `--disable-dns-authority` flag lets operators explicitly opt out even if the server-side is enabled. ### Port 53 notes Port 53 requires root on Linux. If `systemd-resolved` is occupying port 53, either disable it (`sudo systemctl disable --now systemd-resolved`) or bind Newt to a specific IP via `--dns-bind`. ### New dependencies - [`miekg/dns`](https://github.com/miekg/dns): DNS library - [`golang-jwt/jwt/v5`](https://github.com/golang-jwt/jwt): JWT parsing for auth proxy ## How to test? ### Option 1: Full local test stack There's a complete end-to-end test stack in [`mattv8/pangolin-testing`](https://github.com/mattv8/pangolin-testing). It spins up a PostgreSQL, Pangolin, Gerbil, two Newt instances, two backends, and a test client on a Docker bridge network. ```bash git clone https://github.com/mattv8/pangolin-testing testing cd testing/ sudo modprobe wireguard docker compose down -v && docker compose up -d docker compose ps bash scripts/bootstrap.sh ``` Verify: ```bash dig @localhost -p 5353 app.test.dev A +short # → 172.28.0.10 dig @localhost -p 5354 app.test.dev A +short # → 172.28.0.10 dig @localhost -p 5353 anything.test.dev A +short # → 172.28.0.10 (wildcard) ``` Failover: ```bash docker compose stop backend dig @localhost -p 5353 app.test.dev A +short # → secondary IP docker compose start backend ``` Auth proxy: ```bash curl -sI http://localhost:8080/ | grep Location # → 302 redirect to login ``` See the [testing README](https://github.com/mattv8/pangolin-testing/blob/main/README.md) for the architecture diagram and all available test commands. ### Option 2: Drop-in to an existing stack ```bash sudo cp /usr/local/bin/newt /usr/local/bin/newt.official curl -fsSL https://raw.githubusercontent.com/mattv8/pangolin-testing/main/scripts/get-newt.sh | bash sudo systemctl restart newt sudo journalctl -u newt -f # watch for DNS Authority log lines ``` Rollback: ```bash sudo cp /usr/local/bin/newt.official /usr/local/bin/newt && sudo systemctl restart newt ``` You'll also need the companion Pangolin build (see the Pangolin PR) to actually push zone configs. ### See it in action Run this command and watch it rotate between my public IP's (please don't DOS me): ```bash for i in $(seq 1 20); do echo "$(date +%H:%M:%S) $(dig @ns1.postportal.dev.visnovsky.us +short +time=2 +tries=1 postportal.dev.visnovsky.us A | head -1)"; sleep 0.5; done ``` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-19 14:26:34 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/newt#992