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]>
35 lines
2.2 KiB
Plaintext
35 lines
2.2 KiB
Plaintext
# =============================================================================
|
|
# TEMPLATE — NOT APPLIED, NOT ENCRYPTED (.yaml.example is ignored by kustomize and never
|
|
# auto-encrypted by SOPS). Reference scaffold + OPERATOR HAND-OFF.
|
|
#
|
|
# WHAT THIS IS: the credentials JSON of the locally-managed Cloudflare Tunnel that
|
|
# platform/cloudflared runs. `cloudflared tunnel create` writes it; it holds the account tag, the
|
|
# tunnel UUID and the tunnel SECRET. Anyone holding it can run a connector for this tunnel and
|
|
# receive its traffic, so it is a real credential: SOPS-encrypted in git, never printed.
|
|
#
|
|
# *** THE REAL FILE IS COMMITTED WITH REPLACE-ME PLACEHOLDERS, ALREADY ENCRYPTED. ***
|
|
# So the wiring is complete before the tunnel exists: the resource is listed in kustomization.yaml
|
|
# and both overlays already carry the `cloudflared` decryption patch. Until you fill it, the
|
|
# Deployment CrashLoops inside its own NON-GATING Flux Kustomization (clusters/base/cloudflared.yaml,
|
|
# wait:false) and CloudflaredTunnelDown fires. Nothing else in the cluster is affected.
|
|
#
|
|
# HAND-OFF (operator — an agent must not mint a long-lived credential, CLAUDE.md §6).
|
|
# The full procedure, with verification and rollback, is runbooks/cloudflare-tunnel.md. In short:
|
|
# 1. `cloudflared tunnel login` + `cloudflared tunnel create --credentials-file ... home-k3s`
|
|
# (pinned cloudflared image under podman; the toolbox does not ship cloudflared).
|
|
# 2. Write the JSON STRAIGHT INTO the encrypted file with `sops set`, inside the toolbox — the
|
|
# plaintext never reaches a terminal or the repo tree.
|
|
# 3. Put the tunnel UUID (not secret) into platform/cloudflared/config.yaml `tunnel:`.
|
|
# 4. Verify without printing (`sops -d --extract ... | jq -e ...`), then PR it.
|
|
# =============================================================================
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: cloudflared-credentials
|
|
namespace: cloudflared
|
|
type: Opaque
|
|
stringData:
|
|
# One line of JSON, exactly as `cloudflared tunnel create` wrote it (compacted with `jq -c`).
|
|
# TunnelID MUST equal the `tunnel:` UUID in config.yaml.
|
|
credentials.json: '{"AccountTag":"REPLACE-ME","TunnelSecret":"REPLACE-ME","TunnelID":"REPLACE-ME"}'
|