Operator decision on PR #81: no CI job may reach a privileged daemon. The act runner is untouched. - platform/buildkit (+ clusters/base/buildkit.yaml): moby/buildkit v0.34.1-rootless pinned by digest, uid 1000, not privileged; caps drop ALL + SETUID/SETGID, seccomp/AppArmor Unconfined, read-only rootfs (each measured under podman). cert-manager CA + server/client certs, ClusterIP :1234, default-deny with ingress only from the act-runner pod (DinD masquerades jobs to it). No Kyverno exception: every applied policy matches app-namespace=true only. - Each Containerfile names its shipped stage and ends in a `verify` stage holding every former `docker run` assertion (uid 65532, RUN --network=none, writable-path inventory standing in for the read-only rootfs). The old `&& echo` checks that could never fail are real assertions now. - images.sh drives buildkitd with a pinned buildx (sha256-checked) via bake; PRs build verify targets with agent-runner FROM the in-run toolbox (target: context); main verifies, then pushes. Fails loudly when the builder secrets are absent or buildkitd is unreachable. - infra/gitea/buildkit-client-secret.sh copies the client cert into Actions secrets. Co-Authored-By: Claude Opus 5.5 <[email protected]>
89 lines
3.1 KiB
YAML
89 lines
3.1 KiB
YAML
---
|
|
# 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
|