Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa1af65807 |
@@ -0,0 +1,52 @@
|
||||
# Device-facing endpoint, over TLS.
|
||||
#
|
||||
# This replaces the reason the cleartext LoadBalancer in device-service.yaml
|
||||
# was given a hostname at all. That file claimed the firmware "would reject
|
||||
# the internal CA" — but nothing here is signed by an internal CA:
|
||||
# letsencrypt-cluster solves DNS-01 against the renner.uno Cloudflare zone,
|
||||
# so trmnl.renner.uno already serves a public Let's Encrypt certificate
|
||||
# (issuer CN=YR2) that any client with a normal CA bundle trusts. A
|
||||
# LAN-only name gets the same treatment — DNS-01 never needs the host to be
|
||||
# publicly reachable — so the device can speak HTTPS like everything else.
|
||||
#
|
||||
# The hostname moves here from the Service's external-dns annotation rather
|
||||
# than being duplicated: two sources claiming trmnl-device.renner.uno would
|
||||
# have external-dns flapping the record between the Traefik VIP and the
|
||||
# device LB. The LoadBalancer keeps its address and stays reachable at
|
||||
# http://10.2.99.89 as a nameless fallback if TLS ever turns out to be the
|
||||
# thing that breaks.
|
||||
#
|
||||
# CONSEQUENCE, and the reason API_URI in terminus.yaml changes with this:
|
||||
# Traefik's `web` entrypoint carries a global http -> websecure redirect
|
||||
# (helmrelease.yaml: `to: websecure, scheme: https, permanent: true`), so
|
||||
# once this name points at Traefik, http://trmnl-device.renner.uno answers
|
||||
# 308 rather than serving. Whether the firmware follows that is not
|
||||
# documented, so the device is provisioned with the https URL and Terminus
|
||||
# hands back https image_urls to match. No mixed-scheme fetch.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: terminus-device
|
||||
namespace: trmnl
|
||||
# No external-dns hostname annotation: external-dns-unifi runs with
|
||||
# --source=ingress, so it registers the hosts in spec.rules on its own.
|
||||
# Same as the terminus Ingress next door.
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-cluster
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- trmnl-device.renner.uno
|
||||
secretName: trmnl-device-tls
|
||||
rules:
|
||||
- host: trmnl-device.renner.uno
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: terminus
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,15 +1,24 @@
|
||||
# Device-facing endpoint. Cleartext HTTP, deliberately.
|
||||
# Cleartext fallback for the device, reachable by address only.
|
||||
#
|
||||
# The TRMNL firmware initiates every request and cannot be handed the
|
||||
# internal CA, so terminating TLS here would simply break polling. Scope of
|
||||
# the exposure: this Service is LAN-only (no public DNS label, no Cloudflare
|
||||
# record), it carries no admin session — the device authenticates with its
|
||||
# MAC in the `ID` header plus a per-device api_key — and the Terminus admin
|
||||
# UI stays on the TLS route at trmnl.renner.uno.
|
||||
# This used to be THE device endpoint, on the premise that the firmware
|
||||
# "cannot be handed the internal CA". The premise was wrong: nothing here
|
||||
# hands out an internal CA for these names — letsencrypt-cluster solves
|
||||
# DNS-01 against the renner.uno Cloudflare zone and issues publicly-trusted
|
||||
# certificates for LAN-only hosts, which is why trmnl.renner.uno has always
|
||||
# served an issuer CN=YR2 certificate. The device speaks HTTPS via
|
||||
# device-ingress.yaml, which now owns the trmnl-device.renner.uno name.
|
||||
#
|
||||
# Kept, without a hostname, because it is the one path to Terminus that
|
||||
# depends on neither Traefik nor certificate renewal: http://10.2.99.89
|
||||
# still serves /api/setup and /api/display. If TLS is ever what breaks the
|
||||
# panel, the recovery is to type that address into the captive portal.
|
||||
#
|
||||
# Scope of the exposure is unchanged: LAN-only (no public DNS label, no
|
||||
# Cloudflare record), no admin session — the device authenticates with its
|
||||
# MAC in the `ID` header plus a per-device api_key.
|
||||
#
|
||||
# Same shape as home-assistant-bgp: a dedicated address on the Cilium BGP
|
||||
# pool rather than a TLS-less Ingress, which would be a new pattern for this
|
||||
# repo. The device is provisioned with the HOSTNAME, not the address.
|
||||
# pool.
|
||||
#
|
||||
# The address is requested explicitly, matching every other LB service here.
|
||||
# Left to allocate freely, Cilium IPAM handed out the first free address in
|
||||
@@ -30,8 +39,10 @@ metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: terminus
|
||||
lb-pool: bgp
|
||||
# No external-dns hostname: device-ingress.yaml claims that name. Two
|
||||
# sources claiming trmnl-device.renner.uno would flap the record between
|
||||
# the Traefik VIP and this address (external-dns runs --policy=sync).
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: trmnl-device.renner.uno
|
||||
lbipam.cilium.io/ips: "10.2.99.89,fd99::89"
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
|
||||
@@ -6,6 +6,9 @@ resources:
|
||||
- valkey.yaml
|
||||
- terminus.yaml
|
||||
- ingress.yaml
|
||||
# TLS device endpoint (owns trmnl-device.renner.uno) plus the nameless
|
||||
# cleartext LoadBalancer it falls back to.
|
||||
- device-ingress.yaml
|
||||
- device-service.yaml
|
||||
# Headless HA screenshotter. Lives in this namespace because Terminus
|
||||
# FETCHES rendered screens back from it (uri delivery mode), so the
|
||||
|
||||
@@ -7,11 +7,17 @@ data:
|
||||
TZ: "Europe/Berlin"
|
||||
HANAMI_PORT: "2345"
|
||||
# What the device is told to fetch from. Terminus bakes this into the
|
||||
# absolute `image_url` it hands back on /api/display, so it MUST be the
|
||||
# cleartext LAN name, not trmnl.renner.uno — the firmware speaks plain
|
||||
# HTTP and would reject the internal CA. No trailing slash: the same
|
||||
# string is typed into the captive portal at provisioning time.
|
||||
API_URI: "http://trmnl-device.renner.uno"
|
||||
# absolute `image_url` it hands back on /api/display, so it has to be a
|
||||
# name the DEVICE can resolve and fetch — and it has to carry the same
|
||||
# scheme the device polls with, or every screen fetch is a second,
|
||||
# cleartext connection. No trailing slash: the same string is typed into
|
||||
# the captive portal at provisioning time.
|
||||
#
|
||||
# https since device-ingress.yaml took over trmnl-device.renner.uno. The
|
||||
# earlier value was http on the theory that the firmware would reject an
|
||||
# internal CA; there is no internal CA here — letsencrypt-cluster issues
|
||||
# publicly-trusted certs for LAN-only names via DNS-01.
|
||||
API_URI: "https://trmnl-device.renner.uno"
|
||||
KEYVALUE_URL: "redis://terminus-valkey:6379"
|
||||
# Rack::Attack rate-limit bypass. Beyond upstream's RFC1918 defaults this
|
||||
# adds fc00::/7, which covers the pod CIDR (fd10:244::/48), the Cilium LB
|
||||
|
||||
Reference in New Issue
Block a user