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
|
# This used to be THE device endpoint, on the premise that the firmware
|
||||||
# internal CA, so terminating TLS here would simply break polling. Scope of
|
# "cannot be handed the internal CA". The premise was wrong: nothing here
|
||||||
# the exposure: this Service is LAN-only (no public DNS label, no Cloudflare
|
# hands out an internal CA for these names — letsencrypt-cluster solves
|
||||||
# record), it carries no admin session — the device authenticates with its
|
# DNS-01 against the renner.uno Cloudflare zone and issues publicly-trusted
|
||||||
# MAC in the `ID` header plus a per-device api_key — and the Terminus admin
|
# certificates for LAN-only hosts, which is why trmnl.renner.uno has always
|
||||||
# UI stays on the TLS route at trmnl.renner.uno.
|
# 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
|
# 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
|
# pool.
|
||||||
# repo. The device is provisioned with the HOSTNAME, not the address.
|
|
||||||
#
|
#
|
||||||
# The address is requested explicitly, matching every other LB service here.
|
# The address is requested explicitly, matching every other LB service here.
|
||||||
# Left to allocate freely, Cilium IPAM handed out the first free address in
|
# Left to allocate freely, Cilium IPAM handed out the first free address in
|
||||||
@@ -30,8 +39,10 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/name: terminus
|
app.kubernetes.io/name: terminus
|
||||||
lb-pool: bgp
|
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:
|
annotations:
|
||||||
external-dns.alpha.kubernetes.io/hostname: trmnl-device.renner.uno
|
|
||||||
lbipam.cilium.io/ips: "10.2.99.89,fd99::89"
|
lbipam.cilium.io/ips: "10.2.99.89,fd99::89"
|
||||||
spec:
|
spec:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ resources:
|
|||||||
- valkey.yaml
|
- valkey.yaml
|
||||||
- terminus.yaml
|
- terminus.yaml
|
||||||
- ingress.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
|
- device-service.yaml
|
||||||
# Headless HA screenshotter. Lives in this namespace because Terminus
|
# Headless HA screenshotter. Lives in this namespace because Terminus
|
||||||
# FETCHES rendered screens back from it (uri delivery mode), so the
|
# FETCHES rendered screens back from it (uri delivery mode), so the
|
||||||
|
|||||||
@@ -7,11 +7,17 @@ data:
|
|||||||
TZ: "Europe/Berlin"
|
TZ: "Europe/Berlin"
|
||||||
HANAMI_PORT: "2345"
|
HANAMI_PORT: "2345"
|
||||||
# What the device is told to fetch from. Terminus bakes this into the
|
# 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
|
# absolute `image_url` it hands back on /api/display, so it has to be a
|
||||||
# cleartext LAN name, not trmnl.renner.uno — the firmware speaks plain
|
# name the DEVICE can resolve and fetch — and it has to carry the same
|
||||||
# HTTP and would reject the internal CA. No trailing slash: the same
|
# scheme the device polls with, or every screen fetch is a second,
|
||||||
# string is typed into the captive portal at provisioning time.
|
# cleartext connection. No trailing slash: the same string is typed into
|
||||||
API_URI: "http://trmnl-device.renner.uno"
|
# 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"
|
KEYVALUE_URL: "redis://terminus-valkey:6379"
|
||||||
# Rack::Attack rate-limit bypass. Beyond upstream's RFC1918 defaults this
|
# 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
|
# adds fc00::/7, which covers the pod CIDR (fd10:244::/48), the Cilium LB
|
||||||
|
|||||||
Reference in New Issue
Block a user