Files
fancy-dns/deploy/k8s/console/console.yaml
T
matsandClaude Sonnet 5.5 c6c5ca4ff7 Make the resolver pure DNS: JSON access log on stdout instead of a log store
The resolver kept its own query-log store (a bbolt ring, a live ring with SSE
fanout, rolling per-domain counters and dashboard time-series) for the console.
In a multi-node deployment each pod held a different slice of that, so every
view disagreed with itself, and the cost sat on the query path. Charts belong
in Grafana and log search in the log collector, so the store is gone.

internal/accesslog writes one JSON line per notable query to stdout. The default
is what was blocked and what failed (blocked, redirected, SERVFAIL, dropped,
refused); log_cached and sample_rate add ordinary answers for a debugging
session. Lines go through a bounded buffer to a single writer goroutine and are
dropped, and counted in fancydns_access_log_dropped_total, when the stream
cannot keep up, so a stalled log pipe can never stall a query. The config key is
access_log (the old qlog block is ignored, like any unknown key).

The metrics gain what the dashboard used to compute: fancydns_group_queries_total
by ACL group and outcome and fancydns_responses_total by RCODE. Removed with the
store: /api/dashboard, /api/logs, /api/logs/stream, /api/logs/clear,
/api/cache/top, the series rings, and the cache's per-name hit table, which took
a mutex and built a string on every cache hit.

Tests that read the old log now read the access-log lines; the contract test
drops the removed endpoints. The web console still calls them and is changed in
the next commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 09:53:04 +02:00

114 lines
3.7 KiB
YAML

# The console: web UI plus the API behind it, as its own Deployment. It writes
# ClientGroup / BlockList / DNSZone objects and forwards everything else to the
# resolver's admin API. It is not on the DNS path; stopping it changes no answer.
#
# Secrets it needs (create them out of band):
# fancy-dns-console-runtime key FANCYDNS_RUNTIME_KEY : an API key the resolver accepts
# fancy-dns-console-apikey key FANCYDNS_API_KEY : the console's own machine key
apiVersion: v1
kind: ConfigMap
metadata:
name: fancy-dns-console
namespace: dns
data:
console.yaml: |
# The console has no blocklists or listeners of its own.
blocklist: {enabled: false}
api:
enabled: true
listen: ["0.0.0.0:8080"]
base_path: /api
ui: true
auth:
mode: oidc
api_keys: ["${FANCYDNS_API_KEY}"]
oidc_issuer: https://users.k6n.net
oidc_audience: https://dns.k6n.net
oidc_redirect_uri: https://dns.k6n.net/auth/oidc/callback
oidc_client_id: fancy-dns
oidc_write_roles: [admin]
trust_loopback: false
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: fancy-dns-console
namespace: dns
---
# The only component allowed to write the objects.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: fancy-dns-console
namespace: dns
rules:
- apiGroups: [fancydns.k6n.net]
resources: [dnszones, clientgroups, blocklists]
verbs: [get, list, create, update, delete]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: fancy-dns-console
namespace: dns
subjects:
- {kind: ServiceAccount, name: fancy-dns-console, namespace: dns}
roleRef: {apiGroup: rbac.authorization.k8s.io, kind: Role, name: fancy-dns-console}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: fancy-dns-console
namespace: dns
labels: {app.kubernetes.io/name: fancy-dns-console}
spec:
# One replica: OIDC login state and sessions are in memory, as in the
# resolver's console. More than one needs sticky routing.
replicas: 1
selector:
matchLabels: {app.kubernetes.io/name: fancy-dns-console}
template:
metadata:
labels: {app.kubernetes.io/name: fancy-dns-console}
spec:
serviceAccountName: fancy-dns-console
securityContext:
runAsNonRoot: true
runAsUser: 65532
seccompProfile: {type: RuntimeDefault}
containers:
- name: console
image: fancydns/fancy-dns:latest
command: ["/usr/local/bin/fancy-dns-console"]
args:
- -config=/etc/fancy-dns/console.yaml
# A Service in front of the resolver pods. With several replicas, the
# per-pod views (status, cache, upstreams) come from whichever pod answers.
- -runtime-url=http://fancy-dns-admin.dns.svc:8080
env:
- name: FANCYDNS_RUNTIME_KEY
valueFrom: {secretKeyRef: {name: fancy-dns-console-runtime, key: FANCYDNS_RUNTIME_KEY}}
- name: FANCYDNS_API_KEY
valueFrom: {secretKeyRef: {name: fancy-dns-console-apikey, key: FANCYDNS_API_KEY}}
ports: [{name: http, containerPort: 8080}]
readinessProbe:
httpGet: {path: /api/healthz, port: http}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities: {drop: [ALL]}
volumeMounts:
- {name: config, mountPath: /etc/fancy-dns, readOnly: true}
volumes:
- name: config
configMap: {name: fancy-dns-console}
---
apiVersion: v1
kind: Service
metadata:
name: fancy-dns-console
namespace: dns
spec:
selector: {app.kubernetes.io/name: fancy-dns-console}
ports: [{name: http, port: 80, targetPort: http}]