diff --git a/platform/gitea-runner/README.md b/platform/gitea-runner/README.md index 3b7895e..7eb983e 100644 --- a/platform/gitea-runner/README.md +++ b/platform/gitea-runner/README.md @@ -25,6 +25,25 @@ The runner registration token is authoritative in OpenBao at the `gitea-runner-token` Secret. Never put the token in this directory or a Helm command line. +## SPIRE 与 OCI 发布 + +runner Pod 使用专用 ServiceAccount `gitea-actions`,并由精确匹配 namespace、 +ServiceAccount 隐含的 Pod、以及 chart labels 的 `ClusterSPIFFEID` 获得: + +```text +spiffe://ddupan.top/ci/gitea-actions +``` + +SPIFFE CSI socket 同时只读挂载到 runner 和 DinD。act 的 volume allowlist 只允许 +`/run/spire/agent-sockets`;workflow 仍必须在 job container 中显式请求该 bind +mount。原因是 bind mount 由 DinD 内的 dockerd 解析,只挂 runner 容器无法让 job +访问 Workload API。 + +该身份不是通用 registry 管理员。zot 只对明确列出的 CI 镜像仓库授予 +`read/create/update`,不授予 delete 或其他仓库写入。workflow 应获取 +`aud=zot` 的短期 JWT-SVID,并经 stdin 传给 registry client,不得把 JWT、X.509 +SVID 或 Docker auth 写入 workspace/artifact。 + ## Flux 接管状态 该 release 最初通过下述 review-first 流程手动 bootstrap。下一个 GitOps 阶段将 diff --git a/platform/gitea-runner/clusterspiffeid.yaml b/platform/gitea-runner/clusterspiffeid.yaml new file mode 100644 index 0000000..55d8420 --- /dev/null +++ b/platform/gitea-runner/clusterspiffeid.yaml @@ -0,0 +1,17 @@ +apiVersion: spire.spiffe.io/v1alpha1 +kind: ClusterSPIFFEID +metadata: + name: gitea-actions +spec: + className: spire-mgmt-spire + spiffeIDTemplate: spiffe://{{ .TrustDomain }}/ci/gitea-actions + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: gitea-actions + podSelector: + matchLabels: + app.kubernetes.io/instance: gitea-actions + app.kubernetes.io/name: actions-runner + workloadSelectorTemplates: + - k8s:ns:gitea-actions + - k8s:sa:gitea-actions diff --git a/platform/gitea-runner/kustomization.yaml b/platform/gitea-runner/kustomization.yaml index d4c6516..e34e214 100644 --- a/platform/gitea-runner/kustomization.yaml +++ b/platform/gitea-runner/kustomization.yaml @@ -11,6 +11,8 @@ configMapGenerator: - values.yaml=values.yaml resources: - namespace.yaml + - serviceaccount.yaml + - clusterspiffeid.yaml - external-secret.yaml - helmrepository.yaml - helmrelease.yaml diff --git a/platform/gitea-runner/serviceaccount.yaml b/platform/gitea-runner/serviceaccount.yaml new file mode 100644 index 0000000..8a1541f --- /dev/null +++ b/platform/gitea-runner/serviceaccount.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: gitea-actions + namespace: gitea-actions +automountServiceAccountToken: false diff --git a/platform/gitea-runner/values.yaml b/platform/gitea-runner/values.yaml index 4f258a8..f0e218f 100644 --- a/platform/gitea-runner/values.yaml +++ b/platform/gitea-runner/values.yaml @@ -7,6 +7,12 @@ existingSecretKey: token statefulset: replicas: 1 timezone: Etc/UTC + serviceAccountName: gitea-actions + extraVolumes: + - name: spiffe-workload-api + csi: + driver: csi.spiffe.io + readOnly: true securityContext: fsGroup: 1000 # Chart 0.1.1 applies this block to both runner and DinD containers. @@ -27,6 +33,10 @@ statefulset: repository: gitea/runner tag: 2.3.0 pullPolicy: IfNotPresent + extraVolumeMounts: + - name: spiffe-workload-api + mountPath: /run/spire/agent-sockets + readOnly: true config: | log: level: info @@ -42,6 +52,10 @@ statefulset: container: require_docker: true docker_timeout: 300s + # Workflows must still request this exact bind mount explicitly. The + # allowlist prevents arbitrary host paths from reaching job containers. + valid_volumes: + - /run/spire/agent-sockets dind: # The node enforces AppArmor's unprivileged-userns restriction, which blocks @@ -51,6 +65,12 @@ statefulset: repository: docker tag: 29.7.1-dind pullPolicy: IfNotPresent + # Bind mounts are resolved by dockerd, so the CSI socket must exist in the + # DinD container as well as in the runner container. + extraVolumeMounts: + - name: spiffe-workload-api + mountPath: /run/spire/agent-sockets + readOnly: true # k3s uses a 1450-byte pod MTU. Without matching it here, nested Actions # networks advertise 1500 and GitHub TLS packets disappear on the outer # overlay path while direct pod traffic remains healthy.