{{- if .Values.networkPolicy.enabled }} # ============================================================================= # Ingress: who can talk to the relay # ============================================================================= # Three sources: # 1. The cluster Ingress controller (nginx-ingress) — for Threema webhooks # hitting us through the LB. # 2. The portal namespace — calls /admin and reads /metrics. # 3. Tenant namespaces (managed by pieced-operator) — call /api/send. # # Egress: # - DNS (kube-system) # - Threema Gateway: msgapi.threema.ch:443 (FQDN-pinned) # - Postgres in same namespace # - HTTPS to tenant OpenClaw services in tenant namespaces (port 18789) # ============================================================================= apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: pieced-threema-gateway namespace: {{ .Values.namespace }} spec: endpointSelector: matchLabels: app.kubernetes.io/name: pieced-threema-gateway ingress: # nginx-ingress - fromEndpoints: - matchLabels: "k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name": "ingress-nginx" toPorts: - ports: - port: "8080" protocol: TCP # Portal - fromEndpoints: - matchLabels: "k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name": {{ .Values.networkPolicy.portalNamespace | quote }} toPorts: - ports: - port: "8080" protocol: TCP - port: "9090" protocol: TCP # Tenant namespaces (pieced-operator-managed) - fromEndpoints: - matchLabels: {{ .Values.networkPolicy.tenantNamespaceLabel | quote }}: {{ .Values.networkPolicy.tenantNamespaceLabelValue | quote }} toPorts: - ports: - port: "8080" protocol: TCP egress: # DNS — with the proxy interceptor on so toFQDNs rules below # actually work. # # Cilium `toFQDNs` matches against a per-pod identity that is # populated only when the Cilium DNS proxy observes a resolution # for that name. The proxy is enabled per-policy by a `rules.dns` # clause on the DNS egress: without it, DNS resolution still # succeeds (we allow port 53 to kube-system) but Cilium never # learns the resolved IP, so the subsequent TCP connect to # msgapi.threema.ch is denied at egress and the relay logs # "fetch failed" with no further detail. - toEndpoints: - matchLabels: "k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name": "kube-system" toPorts: - ports: - port: "53" protocol: UDP - port: "53" protocol: TCP rules: dns: - matchPattern: "*" # Threema Gateway public API - toFQDNs: - matchName: "msgapi.threema.ch" toPorts: - ports: - port: "443" protocol: TCP # Postgres (same namespace). # # We match on the namespace label rather than `cnpg.io/cluster` # because that CNPG label is not in Cilium's default identity-relevant # label set in most installations — pods labelled that way still get a # generic Cilium identity, so a matchLabels on it won't match anything. # Restricting to port 5432 + same namespace is safe: the only thing # listening on 5432 in this namespace is CNPG. - toEndpoints: - matchLabels: "k8s:io.kubernetes.pod.namespace": {{ .Values.namespace | quote }} toPorts: - ports: - port: "5432" protocol: TCP # Tenant OpenClaw services — port 18790 (Service targetPort). # # Why 18790, not 18789: # OpenClaw's per-tenant Service exposes the gateway as # `port: 18789, targetPort: 18790`. Cilium's socket-LB rewrites # `connect(svc-IP:18789)` to `pod-IP:18790` before the egress policy # hook fires, so the rule must allow the targetPort (18790), not # the Service port. The application's OPENCLAW_URL_TEMPLATE still # uses :18789 (correct — application connects to the Service port). - toEndpoints: - matchLabels: {{ .Values.networkPolicy.tenantNamespaceLabel | quote }}: {{ .Values.networkPolicy.tenantNamespaceLabelValue | quote }} toPorts: - ports: - port: "18790" protocol: TCP {{- end }}