Ingress and DNS
The Gateways, DNS records, certificates, tunnels and lab resolvers that give cluster services a name and a path from the LAN, tailnet or internet.
Ingress gives a cluster service a Gateway address, a Cloudflare DNS name from external-dns and a Let's Encrypt certificate from cert-manager. The lab resolvers, capsule and spore, serve DNS and time to the lab networks.
Private names#
An app attaches an HTTPRoute to its cluster's shared cluster-gateway, or declares its own Gateway. folly's cluster-gateway has one *.lolwtf.ca wildcard listener that admits routes from any namespace. offsite's has one HTTPS listener for each hostname.
external-dns publishes each route's name as an A record at its Gateway's load-balancer address (VIP). The VIP is private, so the name works on the LAN, and over the tailnet for the owner. With policy sync and txtOwnerId set to CLUSTER_NAME, each cluster deletes its own records when their routes go.
Hosts resolve as <host>.lolwtf.ca. The Kubernetes nodes come from folly's nodes file, through static_records in terraform/network/unifi/folly/k8s.tf, and from NODE_ADDRESSES in offsite's topology file, through terraform/network/cloudflare/lolwtf.ca.tf, which also publishes each cluster's API_SERVER_HOSTNAME. Lab hosts come from each lab and rpis entry with an ip in terraform/network/unifi/folly/clients.yaml.
Public names#
| Cloudflare Tunnel | Runs on | Serves |
|---|---|---|
| folly | folly | spire.lolwtf.ca on /.well-known/openid-configuration and /keys, the SPIRE discovery documents that GCP reads. See Identity. |
| offsite | offsite | tf.lolwtf.ca for Atlantis, and voice.lolwtf.ca on /speech-engine for ElevenLabs Speech Engine to reach mate, which verifies each connection's JWT |
| kthx Apps | offsite | Public kthx App names, quick sites at <name>.kthx.dev, the kthx GitHub webhook, and the Bosun build queue at /internal/bosun/ |
Each cluster that serves kthx Apps has an Apps Gateway with its own VIP. An App with reach: private gets an A record at that VIP, and reach: public gets a proxied CNAME to the kthx Apps tunnel.
Lab DNS and time#
capsule, spore and forge are the three anchors. Each runs CoreDNS and chrony through nix/profiles/anchor.nix.
Shared service addresses#
keepalived runs unicast VRRP on each anchor. It moves shared addresses between healthy anchors, as nix/services/anchor-vips.nix declares.
| Name | Topology key | Preferred anchors, in order | Health check |
|---|---|---|---|
ns1.lolwtf.ca | NS1_IP | capsule, forge, spore | CoreDNS answers |
ns2.lolwtf.ca | NS2_IP | forge, spore, capsule | CoreDNS answers |
s3.lolwtf.ca | S3_VIP | capsule, forge, spore | Garage has quorum and answers S3 requests |
The keys come from clusters/folly/config/anchor-topology.json. An unhealthy anchor loses priority to every healthy anchor.
AnchorVipDown fires when a DNS address has no holder or CoreDNS is down. AnchorS3VipDown fires when no anchor serves S3.
DNS and time clients#
- DHCP supplies ns1 and ns2 to the Kubernetes, future and iot networks.
dns.lolwtf.caandtime.lolwtf.capoint at those addresses.- Folly's Talos nodes use them for time, through
TimeSyncConfiginclusters/folly/talos/patches.tf. - NixOS hosts use
networking.timeServersinnix/profiles/fleet.nix.
Resolver behavior#
CoreDNS blocks the StevenBlack hosts list and forwards other queries over TLS to Cloudflare's malware-blocking resolvers. It answers api.smiirl.com with folly's smiirl Gateway address for the Smiirl counter. cloudpi4 runs the same config as a test resolver.
Chrony syncs from NTS servers and polls the other two anchors.
Rules#
- On offsite, an app that shares
cluster-gatewayadds a listener with its hostname and anallowedRoutesnamespace, or its route does not attach. - Each zone that kthx creates App names in needs a
domainFiltersentry in the external-dns HelmRelease, adnsZonesentry in eachletsencrypt-productionissuer, a wildcard listener and certificate on each serving Apps Gateway, and, forreach: public, a*.<zone>rule interraform/network/cloudflare/kthx-engine.tf. Without one, the App deploys but its name does not resolve or answer. - Keep
--annotation-prefixpinned in the external-dns HelmRelease, or external-dns ignores the proxy and controller annotations.
Where it lives#
clusters/base/networking/andclusters/<site>/networking/:cluster-gateway, issuers, external-dns and cloudflaredclusters/offsite/apps/kthx-engine/gateway.yamlandclusters/folly/apps/kthx-engine-target/gateway.yaml: the Apps Gatewaysclusters/base/cluster-settings.yaml:KTHX_ENGINE_DOMAIN, the default zone for App namesterraform/network/cloudflare/: the zones, tunnels and tunnel ingress rulesnix/services/coredns-sinkhole.nixandnix/services/ntp-server.nix: the lab resolvers
Related#
Linked from 11
- clankerbankerA public pay-per-call API at clankerbanker.ca, a kthx built app on offsite, that sells fortunes, dice rolls, storage and model answers to bots for USDC over x402.
- Built appsA kthx built app is a repository or archive that kthx builds into a signed artifact and deploys to Targets on the clusters, GCP, Vercel or Cloudflare.
- capsuleA Raspberry Pi 5 on NVMe that is one of the three lab DNS and time anchors, and runs NetBox.
- cloudpi4A wired Raspberry Pi 4 at folly that is a test DNS resolver and an iperf3 server.
- forgeA Raspberry Pi 5 on NVMe that is the lab's native arm64 build host.
- sporeA Raspberry Pi 5 on NVMe that serves x86 netboot, forge's HTTP boot image, the Talos boot image and Tinkerbell, lab DNS and time, and the SPIRE server.
- Cloud accountsThe Google Cloud projects, Cloudflare zones and Google Workspace domain that OpenTofu declares, and what each one is for.
- NetworkThe two sites, their UniFi gateways and networks, and the tunnel, routes, ingress and tailnet that connect them.
- NetbootThe network boot service on spore, with TFTP and HTTP for folly's boot files and a signed RAM-boot image that forge falls back to.
- Talos bootThe boot server on spore that serves folly's signed iPXE, HookOS and SecureBoot ISO on the bootstrap VLAN, beside fleetd's enrollment name.
- GlossaryThe lab-specific terms that the wiki pages use, what each means, and the page that defines it.