83 lines
3.4 KiB
Django/Jinja
83 lines
3.4 KiB
Django/Jinja
{#
|
|
Managed by Ansible (roles/k3s_traefik) — do not edit on the node.
|
|
|
|
Plain manifests, not a HelmChart — same pattern as
|
|
roles/k3s_metallb/templates/metallb-config.yaml.j2 and
|
|
roles/k3s_cert_manager/templates/cluster-issuer.yaml.j2: CRs belonging to
|
|
charts installed elsewhere, dropped in the auto-deploying directory and
|
|
retried by k3s's deploy controller until the CRDs they need exist.
|
|
|
|
Rendered only when k3s_traefik_dashboard_host is set; tasks/main.yml
|
|
deletes this file when it isn't, and k3s's deploy controller
|
|
garbage-collects what the file created.
|
|
|
|
traefik.io/v1alpha1, not traefik.containo.us/v1alpha1 — the group changed
|
|
with Traefik v3, which is what current k3s bundles.
|
|
-#}
|
|
{# Explicit Certificate rather than the cert-manager.io/cluster-issuer
|
|
annotation every app's Ingress uses: cert-manager watches Ingress
|
|
resources, and this route can't be one (see below). DNS-01, so this
|
|
issues without the hostname resolving anywhere yet. -#}
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Certificate
|
|
metadata:
|
|
name: traefik-dashboard
|
|
namespace: {{ k3s_traefik_namespace }}
|
|
spec:
|
|
secretName: {{ k3s_traefik_dashboard_tls_secret }}
|
|
issuerRef:
|
|
name: {{ k3s_traefik_dashboard_cert_issuer }}
|
|
kind: ClusterIssuer
|
|
dnsNames:
|
|
- {{ k3s_traefik_dashboard_host }}
|
|
---
|
|
{# Authentik, in forward-auth (domain level) mode — see defaults/main.yml for
|
|
why domain level and not single-application. Fails closed: if Authentik is
|
|
down this returns an error rather than passing the request through, which
|
|
is the correct direction and the reason the port-forward path stays. -#}
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: Middleware
|
|
metadata:
|
|
name: {{ k3s_traefik_dashboard_auth_middleware }}
|
|
namespace: {{ k3s_traefik_namespace }}
|
|
spec:
|
|
forwardAuth:
|
|
address: {{ k3s_traefik_dashboard_auth_address }}
|
|
# Traefik strips X-Forwarded-* from client requests by default; Authentik
|
|
# needs them to know which host and scheme the user actually asked for,
|
|
# and builds its redirect back out of them. Safe here because the only
|
|
# thing that can set them is Traefik itself — nothing reaches this
|
|
# middleware without passing through the entrypoint first.
|
|
trustForwardHeader: true
|
|
authResponseHeaders:
|
|
{% for header in k3s_traefik_dashboard_auth_response_headers %}
|
|
- {{ header }}
|
|
{% endfor %}
|
|
---
|
|
{# An IngressRoute rather than an Ingress, and not by preference: the
|
|
dashboard is served by api@internal, a Traefik-internal service with no
|
|
Kubernetes Service behind it, so there is nothing for an Ingress backend
|
|
to name. That single fact is why the Certificate above is explicit and why
|
|
the middleware is attached here rather than by annotation. -#}
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: traefik-dashboard
|
|
namespace: {{ k3s_traefik_namespace }}
|
|
spec:
|
|
entryPoints:
|
|
- websecure
|
|
routes:
|
|
# Both prefixes, because the dashboard is a static bundle under
|
|
# /dashboard/ that reads its data from /api — serving the first without
|
|
# the second gets you a page that loads and then stays empty.
|
|
- kind: Rule
|
|
match: Host(`{{ k3s_traefik_dashboard_host }}`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
|
|
middlewares:
|
|
- name: {{ k3s_traefik_dashboard_auth_middleware }}
|
|
namespace: {{ k3s_traefik_namespace }}
|
|
services:
|
|
- kind: TraefikService
|
|
name: api@internal
|
|
tls:
|
|
secretName: {{ k3s_traefik_dashboard_tls_secret }}
|