Adds platform/cloudflared: a locally-managed tunnel whose ingress rules live in git. LAN/VPN-only hosts (plex, plex-vip, jackett, pihole, pihole-dns, semaphore, qbittorrent, radarr, sonarr, headlamp, unifi, crafty-mc) map to 404. The apex and *.home go to cilium-gateway-shared.gateway over TLS with matchSNItoHost. Last comes a catch-all 404. Nothing routes to the Kubernetes API. - 2-replica Deployment, hard node spread, non-root, pinned digest, PDB - default-deny plus an egress CNP: Cloudflare edge 7844/443, the Gateway, and Gateway backends by gateway-access=shared minus the LAN-only namespaces (needed because of the CVE-2025-30162 L7LB egress re-check) - PodMonitor plus two alerts that fire on absent series, with promtool tests - its own Flux Kustomization (dependsOn platform-config, wait:false, nothing depends on it), plus SOPS decryption patches in both overlays - placeholder credentials (SOPS-encrypted) so it can merge before enrolment - L0 cloudflared-ingress-rules, and a cloudflared_ scrape owner - runbooks/cloudflare-tunnel.md and decisions/2026-11-08-cloudflare-tunnel.md Co-Authored-By: Claude Opus 5.5 <[email protected]>
36 lines
1.8 KiB
YAML
36 lines
1.8 KiB
YAML
---
|
|
# Cloudflare Tunnel connector. Reconciled by its OWN non-gating Flux Kustomization
|
|
# (clusters/base/cloudflared.yaml: dependsOn platform-config, wait:false) — NOT a line in
|
|
# platform/kustomization.yaml. See that file for why; in one line: this Deployment cannot become
|
|
# Ready until the operator enrols the tunnel, and in a gating tier that would stall every app wave.
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
# REQUIRED for the configMapGenerator: a generated ConfigMap inherits no namespace, and kustomize
|
|
# will not rewrite the Deployment's reference to its hashed name across a namespace boundary
|
|
# (measured on platform/vpn-ingress).
|
|
namespace: cloudflared
|
|
resources:
|
|
- namespace.yaml
|
|
- deployment.yaml # Deployment (2 replicas, hard node spread) + PodDisruptionBudget
|
|
# Namespace default-deny + the Prometheus scrape allow + the egress CiliumNetworkPolicy. Keep
|
|
# them in ONE file: a baseline without its scrape allow silently empties the TSDB.
|
|
- networkpolicy.yaml
|
|
- podmonitor.yaml
|
|
- alerts.yaml
|
|
# The tunnel credentials JSON — the ONE secret here. SOPS-encrypted, decrypted per-env by the
|
|
# `cloudflared` Flux Kustomization (both overlays patch it), referenced by name only. Its
|
|
# plaintext template sibling is deliberately NOT named in this file (no-plaintext-secrets).
|
|
# Ships with REPLACE-ME placeholders; runbooks/cloudflare-tunnel.md fills it.
|
|
- cloudflared-credentials.sops.yaml
|
|
|
|
# config.yaml becomes the CONTENT-HASHED ConfigMap `cloudflared-config`, so an edit to the ingress
|
|
# rules or the tunnel UUID changes the pod template and rolls the Deployment. Do NOT set
|
|
# disableNameSuffixHash: the hash is the rollout mechanism.
|
|
configMapGenerator:
|
|
- name: cloudflared-config
|
|
files:
|
|
- config.yaml
|
|
options:
|
|
labels:
|
|
app.kubernetes.io/name: cloudflared
|