--- # Default-deny for the namespace, then two narrow allows. # # WHO MAY CONNECT — AND WHY THE ACT-RUNNER POD IS THE RIGHT SOURCE (measured 2026-10-29). # CI jobs do not run as pods. act_runner starts each job as a container on its DinD sidecar, on a # docker bridge network INSIDE the act-runner pod's network namespace, and dockerd masquerades it: # kubectl -n gitea-actions exec deploy/act-runner -c dind -- iptables -t nat -S POSTROUTING # -A POSTROUTING -s 172.18.0.0/16 ! -o br-c0f13d041ad6 -j MASQUERADE # -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE # So a job's connection leaves with the act-runner POD's IP and therefore Cilium's identity for # that pod (namespace gitea-actions, app.kubernetes.io/name=act-runner). That is exactly what the # ingress rule names. It cannot distinguish one job from another, or a job from act_runner # itself — per-job authentication is the mTLS client certificate, not this policy. What the # policy adds is that NOTHING ELSE in the cluster can even open the port. apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny namespace: buildkit labels: homelab.keithjackson.dev/baseline: default-deny spec: podSelector: {} policyTypes: - Ingress - Egress ingress: [] egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system ports: - protocol: UDP port: 53 - protocol: TCP port: 53 --- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: buildkitd-allow-ci-ingress namespace: buildkit labels: app.kubernetes.io/name: buildkitd spec: endpointSelector: matchLabels: app.kubernetes.io/name: buildkitd ingress: - fromEndpoints: - matchLabels: io.kubernetes.pod.namespace: gitea-actions app.kubernetes.io/name: act-runner toPorts: - ports: - { port: "1234", protocol: TCP } --- # WHAT A BUILD NEEDS TO REACH. Build steps download (dnf mirrors, GitHub releases, dl.k8s.io, # npm, PyPI, Fedora/Docker registries) and the result is pushed to the Gitea registry. # * world 443/80: the downloads. 80 because Fedora's mirror list includes plain-http mirrors # (dnf verifies package GPG signatures, not transport). # * ingress (the Gateway's Envoy, reserved:ingress): the push. gitea.home.keithjackson.dev # resolves in-cluster to the Gateway VIP (split-horizon CoreDNS), and Cilium hands that # traffic to the Gateway, whose identity is `ingress` — the same identity gitea's own # ingress allow admits. # Nothing else in the cluster: not the API server, not other pods. A build step is code from a # pull request. apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: buildkitd-allow-egress namespace: buildkit labels: app.kubernetes.io/name: buildkitd spec: endpointSelector: matchLabels: app.kubernetes.io/name: buildkitd egress: - toEntities: - world toPorts: - ports: - { port: "443", protocol: TCP } - { port: "80", protocol: TCP } - toEntities: - ingress