Ingress classes and certificates¶
To put an app on an ingress, use expose an app. The tables below are generated from the Traefik, cloudflared, cert-manager and external-dns manifests; the prose between them is not.
Classes¶
| Class | Controller chart | Address | Default class | Source |
|---|---|---|---|---|
cloudflare |
cloudflare-tunnel-ingress-controller |
Cloudflare tunnel ankhmorpork-tunnel |
no | k8s/platform/network/cloudflared/values.yaml |
private |
traefik |
192.168.50.130 |
no | k8s/platform/network/traefik/private/values.yaml |
public |
traefik |
192.168.50.129 |
yes | k8s/platform/network/traefik/public/values.yaml |
private is reachable from the LAN only. public is reachable from the LAN and,
paired with a cloudflare Ingress for the same host, from outside — the how-to
has the pairing and the reason. The two Traefik instances are separate
HelmReleases with their own LoadBalancer IP, not one controller with two
entrypoints.
An Ingress that omits ingressClassName lands on the default class. Do not rely
on that — the admission policy requires the field to be set explicitly.
Certificate issuers¶
| Issuer | Challenge | ACME server | Source |
|---|---|---|---|
letsencrypt-dns01 |
DNS-01 (cloudflare) | Let's Encrypt, production | k8s/platform/security/cert-manager/additional/issuer-acme-dns01-cloudflare.yaml |
letsencrypt-prod |
DNS-01 (cloudflare) | Let's Encrypt, production | k8s/platform/security/cert-manager/additional/issuer-acme-http.yaml |
Both issuers solve the same challenge through Cloudflare, so a hostname does not
have to be reachable before its certificate is issued and wildcards work on
either. They differ only in the ACME account key behind them; letsencrypt-prod
is the convention. Both are accepted by the admission policy; anything else is
rejected. Set one with the cert-manager.io/cluster-issuer annotation.
cloudflare Ingresses need no issuer and no TLS block: the tunnel terminates TLS
at Cloudflare's edge.
What admission enforces¶
validate-ingress-contract denies an Ingress that fails any of these. Full
rule text in admission policies.
spec.ingressClassNameis one ofpublic,private,cloudflare- the deprecated
kubernetes.io/ingress.classannotation is absent publicandprivateIngresses setspec.tlspublicandprivateIngresses use an approvedcert-manager.io/cluster-issuer- every TLS entry sets a non-empty
secretName
DNS¶
external-dns writes records into UniFi's resolver — the house's internal
DNS, not a public zone.
| Setting | Value |
|---|---|
| Provider | webhook |
| Domains it will touch | thaum.xyz, krupa.net.pl |
| Policy | sync |
| Ownership | txt registry, txtOwnerId: thaum.xyz, txtPrefix: k8s. |
| Fallback name for a Service with no host | {{.Name}}.{{.Namespace}}.ankhmorpork.thaum.xyz |
| Source | k8s/platform/network/external-dns/values.yaml |
From a cloudflare Ingress, external-dns publishes the tunnel CNAME
(*.cfargotunnel.com), which resolves nowhere on the LAN. This is why a
cloudflare Ingress alone leaves a name that the internal resolver hands out with
no usable address.
Public names resolve off-LAN through the *.krupa.net.pl wildcard CNAME pointing
at Cloudflare. That means an off-LAN client reaching a private-only host will
resolve it, arrive at Cloudflare, and get nothing — the tunnel has no route for
it.
Host naming¶
| Pattern | Meaning |
|---|---|
<name>.ankhmorpork.thaum.xyz |
internal, private class |
<name>.krupa.net.pl |
external, public + cloudflare pair |
Every hostname served is listed in applications, generated from the Ingress manifests and the chart values.