From e513739ba093a5b05007da895530750d05af772e Mon Sep 17 00:00:00 2001 From: panxiao81 Date: Wed, 9 Sep 2026 17:48:40 +0000 Subject: [PATCH] fix(ci): use compatible DinD runner --- CHANGELOG.md | 2 +- docs/cicd.md | 12 +++++++----- platform/gitea-runner/README.md | 14 ++++++++++---- platform/gitea-runner/values.yaml | 12 ++++-------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4163f6..e8f645b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ What changed in this homelab, when, and why. Newest first. | secrets | Recorded that ESO 2.8.0, five ExternalSecrets and the scoped OpenBao Kubernetes-auth path already exist; the next gate is live recovery testing and migration of any remaining manual Secrets | | Terraform | Recorded Gitea 1.27 State Registry as the preferred candidate for local roots after version and recovery testing; the OCI recovery root remains in OCI Object Storage to avoid a home-control-plane dependency loop | | cleanup | Removed the retired NapCat tree, the Contour and Kanidm archive trees, and seven generated Terraform plan files before establishing the clean Git baseline; plans may embed complete state and remain globally ignored | -| CI | Added a review-first Gitea Actions runner bootstrap: official actions chart 0.1.1, pinned runner 2.3.0, one persistent Kubernetes runner with capacity four and rootless DinD, plus an ESO reference to a repository-scoped registration token in OpenBao. It is not deployed until the PR is merged | +| CI | Added a review-first Gitea Actions runner bootstrap: official actions chart 0.1.1, pinned runner 2.3.0, one persistent instance-scoped Kubernetes runner with capacity four, plus an ESO reference to its registration token in OpenBao. The first deployment proved that rootlesskit is blocked by the node's AppArmor unprivileged-userns policy; because the chart requires privileged DinD in either mode, the reviewed fix uses regular DinD instead of weakening the host-wide policy | | identity | Declared the Samba AD `gitea-admins` group with `panxiao81` as its initial member. Gitea already maps this OIDC group to site administrators; the local `gitea_admin` account remains as break-glass access | `Carried forward`: re-verify OpenBao/ESO recovery and remaining Secret inventory; diff --git a/docs/cicd.md b/docs/cicd.md index 6c35f3a..d008335 100644 --- a/docs/cicd.md +++ b/docs/cicd.md @@ -90,11 +90,13 @@ Gitea Actions is the CI control plane. It integrates directly with repository permissions and status checks and preserves GitHub Actions workflow syntax. The bootstrap worker is the official Gitea Runner chart in Kubernetes: one -persistent StatefulSet Pod, rootless Docker-in-Docker and capacity four. Job +persistent StatefulSet Pod, Docker-in-Docker and capacity four. Job containers are dynamic, while the runner and its Docker daemon remain resident. -Rootless DinD still needs a privileged Pod to establish its user namespace, so -the runner is repository-scoped and restricted to trusted workflows. See -`platform/gitea-runner/`. +The chart's DinD container is privileged in both modes. Rootless mode is blocked +by the node's AppArmor unprivileged-userns policy, so regular DinD avoids weakening +that host-wide policy without pretending the Pod has a stronger isolation boundary. +The runner is instance-scoped and restricted to trusted repositories and workflows. +See `platform/gitea-runner/`. This is not native pod-per-job execution. If stronger isolation becomes useful, the runner's ephemeral registration and Gitea `workflow_job` webhook can later @@ -113,7 +115,7 @@ Proxmox provider exists, so ephemeral Proxmox VMs would mean writing one. Bootstrap dependencies and current status: 1. **Secret delivery exists.** OpenBao and External Secrets Operator already - synchronize five Secrets. Add the repository-scoped runner registration token + synchronize five Secrets. Add the instance-scoped runner registration token at `kv/k8s/gitea-runner`; Git contains only its `ExternalSecret` reference. 2. **Git remote exists.** `homelab-infra` is hosted in Gitea. An off-cluster read-only mirror remains required for disaster recovery. diff --git a/platform/gitea-runner/README.md b/platform/gitea-runner/README.md index 2d1e7c1..5ccf153 100644 --- a/platform/gitea-runner/README.md +++ b/platform/gitea-runner/README.md @@ -2,9 +2,14 @@ This is the bootstrap runner for Gitea Actions. One persistent runner Pod accepts up to four jobs; each job runs in a dynamically created container inside a -rootless Docker-in-Docker daemon. Rootless DinD still requires a privileged Pod -to create its user namespace, so this runner is restricted to this repository -and trusted workflows. +Docker-in-Docker daemon. The official chart runs DinD privileged. Rootless DinD +would still be privileged and is blocked by the node's AppArmor user-namespace +policy, so this deployment uses regular DinD instead of weakening that host-wide +policy. Only trusted workflows may target this runner. + +The runner is registered at instance scope so it is available to every repository +on this Gitea instance. Repository permissions and protected-branch review are +therefore the security boundary; do not enable Actions for untrusted repositories. The runner registration token is authoritative in OpenBao at `kv/k8s/gitea-runner`. External Secrets Operator projects its `token` property to @@ -16,7 +21,8 @@ command line. This is a one-time manual deployment because Flux is not installed yet: 1. Merge the reviewed PR. -2. Create a repository-scoped runner registration token in Gitea. +2. As a Gitea site administrator, create an instance-scoped runner registration + token under **Site Administration → Actions → Runners**. 3. Store it as the `token` property at `kv/k8s/gitea-runner` without exposing it in shell history: diff --git a/platform/gitea-runner/values.yaml b/platform/gitea-runner/values.yaml index 5c1079a..ba1260f 100644 --- a/platform/gitea-runner/values.yaml +++ b/platform/gitea-runner/values.yaml @@ -44,14 +44,10 @@ statefulset: docker_timeout: 300s dind: - rootless: true - uid: 1000 + # The node enforces AppArmor's unprivileged-userns restriction, which blocks + # rootlesskit even though this chart must run DinD privileged either way. + rootless: false registry: docker.io repository: docker - tag: 29.7.1-dind-rootless + tag: 29.7.1-dind pullPolicy: IfNotPresent - extraEnvs: - - name: DOCKERD_ROOTLESS_ROOTLESSKIT_NET - value: slirp4netns - - name: DOCKERD_ROOTLESS_ROOTLESSKIT_MTU - value: "65520"