Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aee6a54ad | ||
|
|
8a53171ad0 | ||
|
|
299194247e | ||
|
|
6b6e1e7e04 | ||
|
|
752fcd5d03 | ||
|
|
55cd083484 | ||
|
|
ada3d3d0b4 | ||
|
|
1bd3111912 |
@@ -45,6 +45,7 @@ INGRESS_NS = os.environ.get("INGRESS_NAMESPACE", "ingress")
|
||||
DEFAULT_AUTHZ_FLOW = os.environ.get("DEFAULT_AUTHORIZATION_FLOW", "default-provider-authorization-implicit-consent")
|
||||
INVALIDATION_FLOW = os.environ.get("INVALIDATION_FLOW", "default-provider-invalidation-flow")
|
||||
COOKIE_DOMAIN = os.environ.get("COOKIE_DOMAIN", "renner.uno")
|
||||
AK_BROWSER_URL = os.environ.get("AUTHENTIK_HOST_BROWSER", "https://auth.renner.uno/")
|
||||
INTERVAL = int(os.environ.get("INTERVAL_SECONDS", "60"))
|
||||
HTTP_TIMEOUT = 20
|
||||
|
||||
@@ -208,6 +209,14 @@ def resolve_backend(gate, service):
|
||||
return sp["port"], selector, target
|
||||
|
||||
|
||||
def embedded_config(config):
|
||||
"""The embedded outpost's config with the host the gates depend on. The
|
||||
embedded outpost builds the sign-in redirect from authentik_host, so it is
|
||||
the public URL, which is also Authentik's default for it."""
|
||||
return {**(config or {}), "authentik_host": AK_BROWSER_URL, "authentik_host_insecure": False,
|
||||
"authentik_host_browser": AK_BROWSER_URL}
|
||||
|
||||
|
||||
def provider_body(gate, flows):
|
||||
return {
|
||||
"name": gate["name"],
|
||||
@@ -340,6 +349,14 @@ def embedded_outpost(ak):
|
||||
return found[0]
|
||||
|
||||
|
||||
def ensure_embedded_config(ak):
|
||||
outpost = embedded_outpost(ak)
|
||||
want = embedded_config(outpost.get("config"))
|
||||
if outpost.get("config") != want:
|
||||
ak.req("PATCH", f"outposts/instances/{outpost['pk']}/", {"config": want})
|
||||
LOG.info("embedded outpost: updated config")
|
||||
|
||||
|
||||
def ensure_gate(ak, gate, flows):
|
||||
name = gate["name"]
|
||||
if gate["group"] and ak.one("core/groups/", name=gate["group"]) is None:
|
||||
@@ -468,6 +485,7 @@ def reconcile():
|
||||
sources = [i for i in k8s.get("/apis/networking.k8s.io/v1/ingresses").get("items", []) if is_gated(i)]
|
||||
shared = shared_hosts(sources)
|
||||
flows = {f["slug"]: f["pk"] for f in ak.list("flows/instances/")}
|
||||
ensure_embedded_config(ak)
|
||||
|
||||
desired = set() # (kind, ns, name) of every Kubernetes object some gate wants
|
||||
gates = set() # gate names whose Authentik side should exist
|
||||
|
||||
@@ -166,6 +166,11 @@ class Objects(unittest.TestCase):
|
||||
def test_drift(self):
|
||||
self.assertEqual(c.drift({"a": 1, "b": 2}, {"a": 1, "b": 3}), {"b": 3})
|
||||
|
||||
def test_embedded_config_keeps_other_keys(self):
|
||||
cfg = c.embedded_config({"log_level": "debug", "authentik_host": c.AK_URL})
|
||||
self.assertEqual(cfg, {"log_level": "debug", "authentik_host": c.AK_BROWSER_URL,
|
||||
"authentik_host_insecure": False, "authentik_host_browser": c.AK_BROWSER_URL})
|
||||
|
||||
|
||||
class FakeAuthentik:
|
||||
"""In-memory stand-in for the endpoints the controller uses; records calls."""
|
||||
@@ -294,6 +299,15 @@ class Reconcile(unittest.TestCase):
|
||||
c.embedded_outpost(self.ak)
|
||||
self.assertEqual(self.ak.get(f"outposts/instances/{ldap['pk']}/")["providers"], [7])
|
||||
|
||||
def test_embedded_config(self):
|
||||
c.ensure_embedded_config(self.ak)
|
||||
cfg = self.ak.get(f"outposts/instances/{self.embedded['pk']}/")["config"]
|
||||
self.assertEqual((cfg["log_level"], cfg["authentik_host"], cfg["authentik_host_browser"]),
|
||||
("info", c.AK_BROWSER_URL, c.AK_BROWSER_URL))
|
||||
before = len(self.ak.calls)
|
||||
c.ensure_embedded_config(self.ak)
|
||||
self.assertEqual(self.ak.calls[before:], [])
|
||||
|
||||
def test_provider_moves_from_proxy_mode(self):
|
||||
self.ak.add("providers/proxy/", {"name": self.g["name"], "mode": "proxy",
|
||||
"internal_host": "http://llama-server.ai.svc.cluster.local:8080",
|
||||
|
||||
@@ -70,7 +70,7 @@ spec:
|
||||
mountPath: /ca
|
||||
containers:
|
||||
- name: audiobookshelf
|
||||
image: ghcr.io/advplyr/audiobookshelf:2.37.1 # {"$imagepolicy": "flux-system:audiobookshelf"}
|
||||
image: ghcr.io/advplyr/audiobookshelf:2.37.2 # {"$imagepolicy": "flux-system:audiobookshelf"}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
|
||||
@@ -374,39 +374,10 @@ data:
|
||||
name: lidarr-gate
|
||||
state: absent
|
||||
|
||||
# No `providers`: authentik-gate-sync attaches the gates, and an update
|
||||
# of an existing outpost is partial. `config` is replaced whole, so it
|
||||
# carries every key, kubernetes_namespace included.
|
||||
- model: authentik_outposts.outpost
|
||||
identifiers:
|
||||
name: authentik Embedded Outpost
|
||||
state: present
|
||||
attrs:
|
||||
config:
|
||||
log_level: info
|
||||
# The embedded outpost builds the sign-in redirect from
|
||||
# authentik_host, so it is the public URL.
|
||||
authentik_host: "https://auth.renner.uno/"
|
||||
authentik_host_insecure: false
|
||||
authentik_host_browser: "https://auth.renner.uno/"
|
||||
# A replica whose outpost websocket is down picks up gate changes
|
||||
# only on this interval; the reconnect backoff never resets
|
||||
# (goauthentik/authentik#26463).
|
||||
refresh_interval: "minutes=1"
|
||||
object_naming_template: "ak-outpost-%(name)s"
|
||||
container_image: null
|
||||
docker_labels: null
|
||||
docker_network: ladmin_default
|
||||
docker_map_ports: true
|
||||
kubernetes_namespace: default
|
||||
kubernetes_replicas: 1
|
||||
kubernetes_service_type: ClusterIP
|
||||
kubernetes_disabled_components: []
|
||||
kubernetes_image_pull_secrets: []
|
||||
kubernetes_ingress_annotations: {}
|
||||
kubernetes_ingress_class_name: null
|
||||
kubernetes_ingress_secret_name: "authentik-outpost-tls"
|
||||
kubernetes_json_patches: null
|
||||
# The embedded outpost is not declared here: authentik-gate-sync owns its
|
||||
# providers list (every gate) and the hosts in its config, and a
|
||||
# blueprint entry must carry `providers`, which would detach the gates
|
||||
# on every apply.
|
||||
|
||||
# Shared LDAPS cert for the LDAP Outpost. Authentik's data model
|
||||
# owns the cert per-LDAPProvider (no outpost-level cert field), so
|
||||
|
||||
@@ -114,6 +114,8 @@ spec:
|
||||
env:
|
||||
- name: AK_URL
|
||||
value: http://authentik-server.authentik.svc.cluster.local
|
||||
- name: AUTHENTIK_HOST_BROWSER
|
||||
value: https://auth.renner.uno/
|
||||
- name: DEFAULT_AUTHORIZATION_FLOW
|
||||
value: default-provider-authorization-implicit-consent
|
||||
- name: INTERVAL_SECONDS
|
||||
|
||||
@@ -128,7 +128,7 @@ spec:
|
||||
memory: 32Mi
|
||||
containers:
|
||||
- name: home-assistant
|
||||
image: ghcr.io/home-assistant/home-assistant:2026.10.2 # {"$imagepolicy": "flux-system:home-assistant"}
|
||||
image: ghcr.io/home-assistant/home-assistant:2026.10.3 # {"$imagepolicy": "flux-system:home-assistant"}
|
||||
env:
|
||||
- name: TZ
|
||||
value: Europe/Berlin
|
||||
|
||||
@@ -52,7 +52,7 @@ spec:
|
||||
# stdlib only; Flux keeps the tag in lockstep via the shared image
|
||||
# policy) — no extra dependency.
|
||||
- name: reconcile-publish-ip
|
||||
image: ghcr.io/music-assistant/server:2.10.7 # {"$imagepolicy": "flux-system:music-assistant"}
|
||||
image: ghcr.io/music-assistant/server:2.10.8 # {"$imagepolicy": "flux-system:music-assistant"}
|
||||
command: ["/app/venv/bin/python", "/scripts/reconcile.py"]
|
||||
volumeMounts:
|
||||
- name: data
|
||||
@@ -62,7 +62,7 @@ spec:
|
||||
readOnly: true
|
||||
containers:
|
||||
- name: music-assistant
|
||||
image: ghcr.io/music-assistant/server:2.10.7 # {"$imagepolicy": "flux-system:music-assistant"}
|
||||
image: ghcr.io/music-assistant/server:2.10.8 # {"$imagepolicy": "flux-system:music-assistant"}
|
||||
env:
|
||||
- name: LOG_LEVEL
|
||||
value: info
|
||||
|
||||
@@ -87,11 +87,9 @@ spec:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
# host/remote-node: kubelet probes + node-local reach (Ceph mons on host net)
|
||||
# world: image pulls and llama-server's Hugging Face model download
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
- world
|
||||
# ICMP — egress mirror; see ingress block above.
|
||||
- toEndpoints:
|
||||
- matchExpressions:
|
||||
@@ -166,3 +164,76 @@ spec:
|
||||
- ports:
|
||||
- port: "8080"
|
||||
protocol: TCP
|
||||
---
|
||||
# Hugging Face model download on cold cache (llama-server, llama-embed, wiki-embed).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: models-egress-huggingface
|
||||
namespace: ai
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchExpressions:
|
||||
- key: app.kubernetes.io/name
|
||||
operator: In
|
||||
values:
|
||||
- llama-server
|
||||
- llama-embed
|
||||
- wiki-embed
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "huggingface.co"
|
||||
- matchName: "hf.co"
|
||||
- matchPattern: "*.huggingface.co"
|
||||
- matchPattern: "*.hf.co"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
---
|
||||
# wiki: Anthropic API (distillation) and TypeSafe API (typed judgements).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: wiki-egress-apis
|
||||
namespace: ai
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: wiki
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "api.anthropic.com"
|
||||
- matchName: "api.typesafe.ai"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
@@ -66,11 +66,9 @@ spec:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
# host/remote-node: kubelet probes + node-local reach (Ceph mons on host net)
|
||||
# world: image pulls, OBC S3 endpoint reachable via the cluster's LB IP, migration pipeline API
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
- world
|
||||
# ICMP — egress mirror; see ingress block above.
|
||||
- toEndpoints:
|
||||
- matchExpressions:
|
||||
@@ -94,3 +92,19 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
---
|
||||
# audiobookshelf (metadata providers) and libation (Audible): HTTPS to the internet.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: audiobookshelf-egress-https
|
||||
namespace: audiobookshelf
|
||||
spec:
|
||||
endpointSelector: {}
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
@@ -70,7 +70,6 @@ spec:
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
- world
|
||||
# ICMP — egress mirror.
|
||||
- toEndpoints:
|
||||
- matchExpressions:
|
||||
@@ -94,3 +93,43 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
---
|
||||
# authentik server and worker: SMTP relay (Proton) for mail, HTTPS for
|
||||
# outbound webhooks, OIDC/social sources and update checks.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: authentik-egress
|
||||
namespace: authentik
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: authentik
|
||||
app.kubernetes.io/part-of: authentik
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "smtp.protonmail.ch"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "587"
|
||||
protocol: TCP
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# EGRESS ONLY: an ingress section would flip ingress to default-deny and
|
||||
# break the apiserver -> webhook admission calls.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: default-egress
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
endpointSelector: {}
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
---
|
||||
# Controller: ACME (Let's Encrypt prod + staging), Cloudflare DNS-01 API, and
|
||||
# DNS-01 self-check against the recursive nameservers.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: cert-manager-controller-egress-world
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/component: controller
|
||||
app.kubernetes.io/name: cert-manager
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "acme-v02.api.letsencrypt.org"
|
||||
- matchName: "acme-staging-v02.api.letsencrypt.org"
|
||||
- matchName: "api.cloudflare.com"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
# Mirrors dns01RecursiveNameservers in
|
||||
# kubernetes/infrastructure/cert-manager/helmrelease.yaml.
|
||||
- toCIDR:
|
||||
- 1.1.1.1/32
|
||||
- 8.8.8.8/32
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,34 @@
|
||||
# CNPG instance pods: the barman-cloud plugin sidecar archives WAL and base
|
||||
# backups to Hetzner S3. Additive only: every namespace holding a CNPG cluster
|
||||
# also carries a namespace egress policy covering in-cluster traffic, so
|
||||
# selecting these pods here does not cut anything else.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumClusterwideNetworkPolicy
|
||||
metadata:
|
||||
name: cnpg-barman-s3-egress
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
cnpg.io/podRole: instance
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "fsn1.your-objectstorage.com"
|
||||
- matchPattern: "*.fsn1.your-objectstorage.com"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
@@ -24,10 +24,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY: do NOT
|
||||
# add an egress section to this CNP — that's what broke attempt
|
||||
# 66dbe9f (it transitioned this ns from default-allow egress to
|
||||
# egress-enforced-with-only-ICMP, killing DNS / apiserver / world).
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -50,3 +47,39 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
---
|
||||
# lapi: CAPI + hub index. agent: hub/collection fetch.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: crowdsec-egress-world
|
||||
namespace: crowdsec
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
k8s-app: crowdsec
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
@@ -22,8 +22,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY: do NOT
|
||||
# add an egress section to this CNP.
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -46,3 +45,21 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
|
||||
@@ -48,4 +48,109 @@ spec:
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
---
|
||||
# external-dns (Cloudflare provider): Cloudflare API.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: external-dns-egress
|
||||
namespace: apps
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: external-dns
|
||||
app.kubernetes.io/instance: external-dns
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "api.cloudflare.com"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
---
|
||||
# external-dns-unifi: UniFi controller API on the UDM (UNIFI_HOST).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: external-dns-unifi-egress
|
||||
namespace: apps
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: external-dns
|
||||
app.kubernetes.io/instance: external-dns-unifi
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "udm.renner.uno"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
---
|
||||
# gatus: DNS probes against the UDM resolver by IP; HTTP checks target in-cluster names.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: gatus-egress
|
||||
namespace: apps
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app: gatus
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
---
|
||||
# ical-proxy: fetches caller-supplied calendar feed URLs.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: ical-proxy-egress
|
||||
namespace: apps
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: ical-proxy
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
- port: "80"
|
||||
protocol: TCP
|
||||
|
||||
@@ -92,11 +92,27 @@ spec:
|
||||
- ports:
|
||||
- port: "8644"
|
||||
protocol: TCP
|
||||
# Push mirror to GitHub and other external targets.
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
---
|
||||
# gitea: push mirrors, external webhooks and OIDC/OAuth sources over HTTPS.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: gitea-egress-https
|
||||
namespace: gitea
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: gitea
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
---
|
||||
# Traefik serves git.renner.uno / gitea.renner.uno (:3000) and the gitea-ssh
|
||||
# entrypoint (:2222). Lives beside the baseline so both land in one reconcile.
|
||||
|
||||
@@ -143,10 +143,6 @@ spec:
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
# World: IoT-VLAN devices, HA Cloud, object storage, and third-party
|
||||
# integration endpoints on the LAN and internet.
|
||||
- toEntities:
|
||||
- world
|
||||
# ICMP — egress mirror of the ingress ICMP allow above. Lets HA
|
||||
# send ICMP to any cluster pod (covers the kernel's ICMPv6
|
||||
# Destination Unreachable when CoreDNS responses land on a
|
||||
@@ -261,10 +257,7 @@ spec:
|
||||
# hairpin off the home-assistant-bgp LoadBalancer and are unusable from a
|
||||
# pod. It reaches HA at home-assistant-bgp.home-assistant.svc.cluster.local.
|
||||
#
|
||||
# Only the ingress half is needed here. Unlike the openbao rotator, the trmnl
|
||||
# namespace has no default-deny EGRESS covering this pod — terminus-egress is
|
||||
# scoped to the Terminus pods by label and does not select the renderer — so
|
||||
# there is no source-side rule to add.
|
||||
# The egress half is trmnl-baseline-egress (toEntities: cluster).
|
||||
#
|
||||
# Source scoped to the renderer pod specifically, not the whole trmnl
|
||||
# namespace: Terminus itself sits in that namespace and has no business
|
||||
@@ -351,3 +344,142 @@ spec:
|
||||
- ports:
|
||||
- port: "5432"
|
||||
protocol: TCP
|
||||
---
|
||||
# home-assistant: IoT-VLAN devices, HA Cloud, and third-party integration
|
||||
# endpoints on the LAN and internet.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: home-assistant-egress-world
|
||||
namespace: home-assistant
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: home-assistant
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
---
|
||||
# shelly-manager: HTTP RPC to Shelly devices on the IoT VLAN.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: shelly-manager-egress
|
||||
namespace: home-assistant
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: shelly-manager
|
||||
egress:
|
||||
- toCIDR:
|
||||
- 10.2.30.0/24
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "80"
|
||||
protocol: TCP
|
||||
---
|
||||
# esphome: OTA/API to devices on the IoT VLAN; HTTPS for GitHub, PlatformIO and PyPI during builds.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: esphome-egress
|
||||
namespace: home-assistant
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: esphome
|
||||
egress:
|
||||
- toCIDR:
|
||||
- 10.2.30.0/24
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
---
|
||||
# zigbee2mqtt: Zigbee coordinator (SLZB) TCP socket.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: zigbee2mqtt-egress
|
||||
namespace: home-assistant
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: zigbee2mqtt
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "slzb-zigbee.renner.uno"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "6638"
|
||||
protocol: TCP
|
||||
---
|
||||
# mqtt-account-controller: credential delivery to edge-1 (deliver.esp32 in mqtt-accounts.yaml).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: mqtt-account-controller-egress
|
||||
namespace: home-assistant
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: mqtt-account-controller
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "edge-1.iot.renner.uno"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "8443"
|
||||
protocol: TCP
|
||||
---
|
||||
# whisper and speech-to-phrase: model downloads over HTTPS.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: speech-models-egress
|
||||
namespace: home-assistant
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchExpressions:
|
||||
- key: app.kubernetes.io/name
|
||||
operator: In
|
||||
values:
|
||||
- whisper
|
||||
- speech-to-phrase
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
@@ -33,7 +33,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY.
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -56,3 +56,41 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
---
|
||||
# immich-server and machine-learning: HTTPS to the internet (model downloads, metadata/reverse geocoding, version checks).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: immich-egress-world
|
||||
namespace: immich
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchExpressions:
|
||||
- key: app.kubernetes.io/name
|
||||
operator: In
|
||||
values: [immich-server, immich-machine-learning]
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
@@ -33,7 +33,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY.
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -56,3 +56,43 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
---
|
||||
# Token job pods install tooling at runtime (apt, dl.k8s.io).
|
||||
# Selected by the job-controller `job-name` label, so the influxdb StatefulSet pod gets no world egress.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: influxdb-token-jobs-egress-world
|
||||
namespace: influxdb
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchExpressions:
|
||||
- key: job-name
|
||||
operator: Exists
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
- port: "80"
|
||||
protocol: TCP
|
||||
|
||||
@@ -9,6 +9,7 @@ resources:
|
||||
- audiobookshelf-ns.yaml
|
||||
- home-assistant-ns.yaml
|
||||
- spegel-ns.yaml
|
||||
- cert-manager-ns.yaml
|
||||
- crowdsec-ns.yaml
|
||||
- database-ns.yaml
|
||||
- immich-ns.yaml
|
||||
@@ -37,4 +38,5 @@ resources:
|
||||
- renovate-ns.yaml
|
||||
- hermes-ns.yaml
|
||||
- allow-cilium-health.yaml
|
||||
- cnpg-barman-s3.yaml
|
||||
- kube-system-hubble-relay.yaml
|
||||
|
||||
@@ -33,7 +33,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY.
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -58,8 +58,7 @@ spec:
|
||||
- { type: 143, family: IPv6 }
|
||||
---
|
||||
# Egress for the app pods (synapse, mas, element-web),
|
||||
# selected by part-of so the mx-pg CNPG pods keep unrestricted egress for
|
||||
# the barman-cloud WAL archive to Hetzner (same trade as trmnl-ns.yaml).
|
||||
# selected by part-of; the mx-pg CNPG pods are covered by mx-pg-egress.
|
||||
#
|
||||
# Nothing here reaches the internet: that is the network half of
|
||||
# "federation off". The one exception is synapse-push-egress below.
|
||||
@@ -187,3 +186,32 @@ spec:
|
||||
- ports:
|
||||
- port: "8443"
|
||||
protocol: TCP
|
||||
---
|
||||
# mx-pg CNPG pods: in-cluster + DNS. Unselected by the app egress policies above;
|
||||
# S3 backup egress comes from the clusterwide CNPG policy.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: mx-pg-egress
|
||||
namespace: matrix
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
cnpg.io/cluster: mx-pg
|
||||
egress:
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
|
||||
@@ -34,7 +34,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY.
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -57,6 +57,24 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
---
|
||||
# Hermes Agent (hermes ns) reads metrics, alerts and logs: the Prometheus,
|
||||
# Alertmanager and Loki HTTP APIs, scoped to those pods and ports.
|
||||
@@ -84,3 +102,120 @@ spec:
|
||||
protocol: TCP
|
||||
- port: "3100"
|
||||
protocol: TCP
|
||||
---
|
||||
# Alertmanager: SMTP submission (smtp_smarthost in helmrelease-prometheus.yaml). Only receiver is email.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: alertmanager-egress-world
|
||||
namespace: monitoring
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: alertmanager
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "smtp.protonmail.ch"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "587"
|
||||
protocol: TCP
|
||||
---
|
||||
# Prober: targets are defined by Probe objects (monitoring-rules), any port.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: blackbox-exporter-egress-world
|
||||
namespace: monitoring
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: prometheus-blackbox-exporter
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
---
|
||||
# Grafana: plugin download (grafana.com) + OAuth, and the legacy Prometheus datasource.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: grafana-egress-world
|
||||
namespace: monitoring
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: grafana
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
# Datasource "Prometheus (legacy)".
|
||||
- toFQDNs:
|
||||
- matchName: "prometheus.srv.renner.uno"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "9090"
|
||||
protocol: TCP
|
||||
---
|
||||
# Prometheus: off-site Uptime Kuma scrape (additionalScrapeConfigs job uptime-kuma). No remoteWrite configured.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: prometheus-egress-world
|
||||
namespace: monitoring
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: prometheus
|
||||
egress:
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "kuma.renner.uno"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
@@ -24,6 +24,10 @@ spec:
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toEntities:
|
||||
- kube-apiserver
|
||||
- toEndpoints:
|
||||
@@ -34,9 +38,9 @@ spec:
|
||||
- ports:
|
||||
- port: "8200"
|
||||
protocol: TCP
|
||||
# NetBird management API (netbird.renner.uno).
|
||||
- toEntities:
|
||||
- world
|
||||
# NetBird management API.
|
||||
- toFQDNs:
|
||||
- matchName: "netbird.renner.uno"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
|
||||
@@ -88,7 +88,6 @@ spec:
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
- world
|
||||
# ICMP — egress mirror.
|
||||
- toEndpoints:
|
||||
- matchExpressions:
|
||||
@@ -268,3 +267,49 @@ spec:
|
||||
- ports:
|
||||
- port: "8000"
|
||||
protocol: TCP
|
||||
---
|
||||
# protonmail-bridge: Proton API (HTTPS) and update/status endpoints (HTTP).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: protonmail-bridge-egress
|
||||
namespace: paperless
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: protonmail-bridge
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
- port: "80"
|
||||
protocol: TCP
|
||||
---
|
||||
# syncthing: relays/discovery (443), STUN (3478), peer sync (22000), local discovery (21027).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: syncthing-egress
|
||||
namespace: paperless
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: syncthing
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
- port: "3478"
|
||||
protocol: UDP
|
||||
- port: "22000"
|
||||
protocol: TCP
|
||||
- port: "22000"
|
||||
protocol: UDP
|
||||
- port: "21027"
|
||||
protocol: UDP
|
||||
|
||||
@@ -53,14 +53,20 @@ spec:
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
# gitea.renner.uno via Traefik.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": ingress
|
||||
app.kubernetes.io/name: traefik
|
||||
# api.mistral.ai, api.anthropic.com, api.typesafe.ai.
|
||||
- toEntities:
|
||||
- world
|
||||
# Model APIs.
|
||||
- toFQDNs:
|
||||
- matchName: "api.mistral.ai"
|
||||
- matchName: "api.anthropic.com"
|
||||
- matchName: "api.typesafe.ai"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
|
||||
@@ -54,12 +54,10 @@ spec:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
# host/remote-node: kube-apiserver (leader election Lease) + cross-node peers;
|
||||
# world: fallback pulls to docker.io/quay.io/ghcr.io/registry.k8s.io.
|
||||
# host/remote-node: kube-apiserver (leader election Lease) + cross-node peers
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
- world
|
||||
# ICMP — egress mirror.
|
||||
- toEndpoints:
|
||||
- matchExpressions:
|
||||
|
||||
@@ -33,7 +33,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY.
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -86,10 +86,9 @@ spec:
|
||||
---
|
||||
# Egress allowlist for the Terminus pod only.
|
||||
#
|
||||
# Deliberately NOT applied to the tr-pg CNPG pods: selecting them here
|
||||
# would make their egress restricted too, and the barman-cloud WAL archive
|
||||
# path to Hetzner object storage is not worth putting behind an FQDN rule
|
||||
# that fails closed. They keep unrestricted egress, matching immich/authentik.
|
||||
# Deliberately NOT applied to the other pods: they are covered by
|
||||
# trmnl-baseline-egress (in-cluster + DNS), and the tr-pg barman-cloud WAL
|
||||
# archive egress comes from the clusterwide CNPG policy.
|
||||
#
|
||||
# Terminus needs exactly three outbound destinations, all HTTPS:
|
||||
# - trmnl.com → GET /api/models, /api/palettes (MODEL_SYNCHRONIZER,
|
||||
@@ -152,3 +151,34 @@ spec:
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
---
|
||||
# In-cluster + DNS for every pod except terminus (terminus-egress is its
|
||||
# allowlist; selecting it here would widen it to all of `cluster`).
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: trmnl-baseline-egress
|
||||
namespace: trmnl
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchExpressions:
|
||||
- key: app.kubernetes.io/name
|
||||
operator: NotIn
|
||||
values: [terminus]
|
||||
egress:
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
|
||||
@@ -40,14 +40,18 @@ spec:
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
# EndpointMonitor watch, Ingress reads, and the startup GET of the config
|
||||
# Secret.
|
||||
- toEntities:
|
||||
- kube-apiserver
|
||||
# api.uptimerobot.com. Not reached at all until an EndpointMonitor exists:
|
||||
# the controller makes no API call at startup.
|
||||
- toEntities:
|
||||
- world
|
||||
- toFQDNs:
|
||||
- matchName: "api.uptimerobot.com"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
|
||||
@@ -19,7 +19,7 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
|
||||
# home-assistant-ns.yaml for the rationale. INGRESS ONLY.
|
||||
# home-assistant-ns.yaml for the rationale.
|
||||
- fromEndpoints:
|
||||
- matchExpressions:
|
||||
- key: io.kubernetes.pod.namespace
|
||||
@@ -42,6 +42,32 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn the toFQDNs mapping.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
# Hetzner S3: velero, node-agent and kopia maintenance jobs.
|
||||
- toFQDNs:
|
||||
- matchName: "fsn1.your-objectstorage.com"
|
||||
- matchPattern: "*.fsn1.your-objectstorage.com"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
---
|
||||
# backup-verify CronJob: kube-apiserver, DNS, Hetzner Cloud API, SSH to its VM.
|
||||
apiVersion: cilium.io/v2
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
# belongs in its own policy with its own selector, as
|
||||
# `wp-pg-allow-cnpg-operator` below does.
|
||||
#
|
||||
# There is no egress section, so egress is unrestricted. Still open (#433).
|
||||
# Egress: in-cluster + DNS only (server, agent, wp-pg). The CNPG S3 backup
|
||||
# egress comes from the clusterwide CNPG policy.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
@@ -36,7 +37,6 @@ spec:
|
||||
- host
|
||||
- remote-node
|
||||
# ICMP — from any cluster pod. See home-assistant-ns.yaml for the rationale.
|
||||
# INGRESS ONLY: do NOT add an egress section to this CNP.
|
||||
#
|
||||
# Needed here specifically because wp-pg-allow-cnpg-operator below attaches
|
||||
# an L4 rule (toPorts :8000) to the wp-pg pods, and Cilium blocks ICMP to an
|
||||
@@ -79,6 +79,24 @@ spec:
|
||||
# instance manager. It lands in stage 2 as its own policy selecting the
|
||||
# server pod, the way woodpecker-allow-rotators already scopes its :8000
|
||||
# rule in apps/woodpecker/networkpolicy.yaml.
|
||||
egress:
|
||||
# All in-cluster destinations (pods, nodes, kube-apiserver).
|
||||
- toEntities:
|
||||
- cluster
|
||||
# rules.dns lets Cilium learn FQDN mappings.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
---
|
||||
# The CNPG operator polls each instance's status endpoint over HTTPS
|
||||
# (https://<pod-ip>:8000/pg/status) to populate Cluster status. Without it the
|
||||
|
||||
@@ -85,13 +85,31 @@ spec:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
# world covers two things WordPress genuinely needs outbound: the
|
||||
# wordpress.org update/plugin API, and the Hetzner Object Storage
|
||||
# endpoint the MariaDB Backup writes to.
|
||||
- toEntities:
|
||||
- host
|
||||
- remote-node
|
||||
- world
|
||||
# Hetzner Object Storage for the MariaDB backup CronJob pods (no stable
|
||||
# label, hence namespace-wide). rules.dns lets Cilium learn the mapping.
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": kube-system
|
||||
k8s-app: kube-dns
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "53"
|
||||
protocol: UDP
|
||||
- port: "53"
|
||||
protocol: TCP
|
||||
rules:
|
||||
dns:
|
||||
- matchPattern: "*"
|
||||
- toFQDNs:
|
||||
- matchName: "fsn1.your-objectstorage.com"
|
||||
- matchPattern: "*.fsn1.your-objectstorage.com"
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
# ICMP — egress mirror.
|
||||
- toEndpoints:
|
||||
- matchExpressions:
|
||||
@@ -115,3 +133,21 @@ spec:
|
||||
- { type: 135, family: IPv6 }
|
||||
- { type: 136, family: IPv6 }
|
||||
- { type: 143, family: IPv6 }
|
||||
---
|
||||
# wordpress: wordpress.org update/plugin API and other HTTPS fetches.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: wordpress-egress-https
|
||||
namespace: wordpress
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: wordpress
|
||||
egress:
|
||||
- toEntities:
|
||||
- world
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "443"
|
||||
protocol: TCP
|
||||
|
||||
Reference in New Issue
Block a user