From 390eb2d835f8caf3022a9068fb52870712855182 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Mon, 22 Jun 2026 16:17:33 -0500 Subject: [PATCH] cleanup --- ansible/CLAUDE.md | 5 +- ansible/README.md | 6 +- .../plans/2026-05-14-resolver-doh-design.md | 72 ------------------- ansible/host_vars/resolver1.vntx.net.yml | 4 -- ansible/host_vars/resolver2.vntx.net.yml | 4 -- .../caddy/templates/Caddyfile-resolver.j2 | 35 --------- ansible/roles/telegraf/defaults/main.yml | 11 +-- 7 files changed, 6 insertions(+), 131 deletions(-) delete mode 100644 ansible/docs/plans/2026-05-14-resolver-doh-design.md delete mode 100644 ansible/host_vars/resolver1.vntx.net.yml delete mode 100644 ansible/host_vars/resolver2.vntx.net.yml delete mode 100644 ansible/roles/caddy/templates/Caddyfile-resolver.j2 diff --git a/ansible/CLAUDE.md b/ansible/CLAUDE.md index e789e2c..54b2f32 100644 --- a/ansible/CLAUDE.md +++ b/ansible/CLAUDE.md @@ -49,7 +49,7 @@ ansible-playbook --check playbook.yml ## Architecture ### Playbook Structure -- `playbook.yml` - Main playbook for all configuration (common, firewall, resolvers, DNS, Caddy, general, monitoring, PostgreSQL, prometheus stack, etc.) +- `playbook.yml` - Main playbook for all configuration (common, firewall, DNS, Caddy, general, monitoring, PostgreSQL, prometheus stack, etc.) - `bootstrap.yml` - Initial host preparation - `netbox.yml` - Standalone NetBox deployment @@ -67,7 +67,6 @@ Roles follow a standard structure with: - `caddy` - Web server and reverse proxy - `firewall` - UFW/firewalld rule management - `ns` - BIND9 nameserver configuration -- `resolvers` - Unbound DNS resolver setup - `tailscale` - Tailscale VPN setup - `monitor` - Icinga2 monitoring master - `prometheus` / `alertmanager` / `loki` / `grafana` / `node_exporter` - Prometheus monitoring stack @@ -101,7 +100,7 @@ Roles follow a standard structure with: - Passwordless sudo configured for automation ### Network Services -- DNS resolvers use Unbound +- DNS resolvers are Flatcar VMs managed via OpenTofu + Butane (see ../tofu/) - Nameservers configured via ns role - Caddy serves as reverse proxy for web services - Tailscale provides VPN connectivity diff --git a/ansible/README.md b/ansible/README.md index 1eb65cd..3a04cfd 100755 --- a/ansible/README.md +++ b/ansible/README.md @@ -13,8 +13,7 @@ This repository contains Ansible playbooks and roles for managing infrastructure ├── requirements.yml # Collection and role dependencies ├── group_vars/ # Group-specific variables │ ├── all/ # Global variables -│ ├── bind9_servers/ # BIND9 zone configurations -│ └── resolvers/ # Resolver configurations +│ └── bind9_servers/ # BIND9 zone configurations ├── host_vars/ # Host-specific variables ├── vars/ # Legacy base variables ├── roles/ # Ansible roles (26 roles) @@ -23,7 +22,6 @@ This repository contains Ansible playbooks and roles for managing infrastructure │ ├── caddy/ # Caddy web server │ ├── firewall/ # UFW/firewalld management │ ├── ns/ # BIND9 nameserver -│ ├── resolvers/ # Unbound DNS resolver │ ├── tailscale/ # Tailscale VPN │ ├── monitor/ # Icinga2 monitoring │ ├── prometheus/ # Prometheus monitoring stack @@ -60,7 +58,6 @@ ansible-playbook -t caddy playbook.yml - `vntx_servers` - VNTX network services (logs, radius, vpn, netbox, unimus, monitor, librenms, uisp) - `home_servers` - Home network services (skippy, mail, dokku, aprs, staging, prom) - `bind9_servers` - BIND9 authoritative nameservers -- `resolvers` - Unbound DNS resolvers - `caddy_servers` - Servers running Caddy web server - `monitoring_servers` - Icinga2 monitoring master - `prometheus_servers` - Prometheus monitoring stack @@ -78,7 +75,6 @@ See `hosts` file for the full inventory. - Tailscale VPN integration - Caddy web server with automatic SSL - BIND9 authoritative DNS with DNSSEC -- Unbound DNS resolvers - Icinga2 monitoring with PagerDuty integration - Prometheus/Grafana/Loki monitoring stack - NetBox IPAM/DCIM diff --git a/ansible/docs/plans/2026-05-14-resolver-doh-design.md b/ansible/docs/plans/2026-05-14-resolver-doh-design.md deleted file mode 100644 index 1f77ae9..0000000 --- a/ansible/docs/plans/2026-05-14-resolver-doh-design.md +++ /dev/null @@ -1,72 +0,0 @@ -# DoH on resolver1/resolver2 with Caddy-managed TLS - -**Date:** 2026-05-14 -**Status:** In Progress - -## Goal - -Serve DNS-over-HTTPS (RFC 8484) from `resolver1.vntx.net` and `resolver2.vntx.net`, -with Let's Encrypt certificate lifecycle handled by Caddy. Also add AAAA records for -the resolvers so they are reachable over IPv6. - -## Architecture - -Each resolver host runs two cooperating services: - -``` - Internet (DoH client) - | HTTPS :443 (resolverN.vntx.net/dns-query) - v - Caddy (new on host) <- obtains/renews LE cert via HTTP-01 on :80 - | HTTP/2 cleartext (h2c), 127.0.0.1:8080/dns-query - v - Unbound (existing) :53 plain DNS (unchanged) - :8080 DoH, http-notls-downstream -``` - -- Caddy owns :443 and :80, manages the LE cert for `resolverN.vntx.net`. -- Unbound serves DoH as cleartext HTTP/2 on loopback only — no certs touch Unbound. -- Plain DNS on :53 is untouched; this change is purely additive. - -## Access control - -DoH clients reach Caddy, which forwards from 127.0.0.1 — so Unbound's source-IP -`access-control` cannot see the real client. Caddy therefore enforces the client -allow-list with a `remote_ip` matcher; non-allowed clients get 403. The allow-list -lives in one place: `resolver_allowed_netblocks` in `group_vars/resolvers/main.yml`, -consumed by both the Caddy matcher and Unbound's `access-control` (for :53). - -## Changes - -### IPv6 / DNS -- `roles/ns/templates/zone.j2` — emit AAAA records when a host has `ipv6:`. -- `group_vars/bind9_servers/vntx.net.yml` — add `ipv6:` to resolver1/2 + resolver-01/02 - (`2606:1c80::240`, `2606:1c80::250`). - -### Resolver group vars -- `group_vars/resolvers/main.yml` — add `resolver_allowed_netblocks`, add 80/443 to - `firewall_allow_rules`, set `caddy_template: Caddyfile-resolver.j2`. - -### Unbound -- `roles/resolvers/templates/unbound.conf.j2` — add loopback DoH listener - (`interface: 127.0.0.1@8080`, `https-port: 8080`, `http-endpoint`, - `http-notls-downstream: yes`); drive `access-control` from - `resolver_allowed_netblocks`. - -### Caddy role -- `roles/caddy/tasks/main.yml` — add RedHat (COPR) install path; support a - `caddy_template` variable; ensure `/var/log/caddy` exists. -- `roles/caddy/templates/Caddyfile-resolver.j2` — new shared template for resolvers. - -### Playbook -- `playbook.yml` — add the `caddy` role to the `resolvers` play. - -## Verification - -- `ansible-playbook --syntax-check playbook.yml` -- After apply: `unbound -V | grep nghttp2` (DoH build support), `ss -tlnp` shows - unbound on 127.0.0.1:8080 and caddy on :443/:80. -- `curl -H 'accept: application/dns-message' https://resolver1.vntx.net/dns-query?dns=...` - from an allowed netblock; 403 from outside. -- `dig AAAA resolver1.vntx.net` returns `2606:1c80::240`. - diff --git a/ansible/host_vars/resolver1.vntx.net.yml b/ansible/host_vars/resolver1.vntx.net.yml deleted file mode 100644 index 1b9abcb..0000000 --- a/ansible/host_vars/resolver1.vntx.net.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -ansible_host: 204.110.191.240 -ansible_python_interpreter: /usr/bin/python3 -ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new' diff --git a/ansible/host_vars/resolver2.vntx.net.yml b/ansible/host_vars/resolver2.vntx.net.yml deleted file mode 100644 index ef1ae45..0000000 --- a/ansible/host_vars/resolver2.vntx.net.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -ansible_host: 204.110.191.250 -ansible_python_interpreter: /usr/bin/python3 -ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new' diff --git a/ansible/roles/caddy/templates/Caddyfile-resolver.j2 b/ansible/roles/caddy/templates/Caddyfile-resolver.j2 deleted file mode 100644 index 3e5d02f..0000000 --- a/ansible/roles/caddy/templates/Caddyfile-resolver.j2 +++ /dev/null @@ -1,35 +0,0 @@ -# Managed by Ansible (roles/caddy) - shared by the [resolvers] group. -# Terminates TLS for the DNS-over-HTTPS endpoint and reverse-proxies to the -# local Unbound DoH listener (cleartext HTTP/2 on 127.0.0.1:8080). -{ - admin off - persist_config off -} - -{{ inventory_hostname }} { - # Restrict DoH to the same netblocks Unbound allows for plain DNS. - # Caddy forwards from 127.0.0.1, so Unbound cannot see the real client; - # the allow-list is enforced here instead. - @allowed remote_ip {% for nb in resolver_allowed_netblocks %}{{ nb }} {% endfor %} - - - handle /dns-query { - handle @allowed { - reverse_proxy 127.0.0.1:8080 { - transport http { - versions h2c 2 - } - } - } - respond "Forbidden" 403 - } - - handle { - respond "DNS-over-HTTPS endpoint: /dns-query" 200 - } - - log { - output file /var/log/caddy/{{ inventory_hostname }}.log - format json - } -} diff --git a/ansible/roles/telegraf/defaults/main.yml b/ansible/roles/telegraf/defaults/main.yml index 8780d88..52e71c3 100644 --- a/ansible/roles/telegraf/defaults/main.yml +++ b/ansible/roles/telegraf/defaults/main.yml @@ -1,17 +1,12 @@ --- -# Telegraf agent: collects Unbound stats via unbound-control and exposes them -# as a Prometheus /metrics endpoint for the prom.w5isp.com server to scrape. -# (unbound-control runs fine as the unprivileged telegraf user because the -# resolvers' control interface is plaintext on localhost.) +# Telegraf agent defaults. For Unbound stats on Flatcar resolvers, see +# tofu/flatcar-resolver.bu (Docker-based Telegraf deployed via Butane). telegraf_interval: "30s" telegraf_unbound_binary: /usr/sbin/unbound-control - -# Prometheus output — Prometheus scrapes http://:/metrics. telegraf_prometheus_port: 9273 telegraf_prometheus_listen: "0.0.0.0:{{ telegraf_prometheus_port }}" -# Only this source network may reach the metrics port (the routed scrape -# path from prom.w5isp.com). Keeps Unbound stats off the public internet. +# Source network allowed to reach the metrics port. telegraf_scrape_allow_cidr: "204.110.188.0/22" # InfluxData package repository (EL/RedHat).