Add Gitea Actions deploy pipeline + deployer RBAC

- .gitea/workflows/deploy.yaml: PRs run a server-side dry-run; pushes to
  main apply the kustomization and wait for all rollouts. Modeled on
  socktop-webterm's pipeline; uses the same KUBECONFIG secret convention
  and gitea-deployer ServiceAccount.
- rbac/gitea-deployer.yaml: ClusterRole/Binding (admin bootstrap, outside
  the root kustomization) — repo resource kinds only, no secrets access,
  no delete verbs, no RBAC escalation. Applied to the cluster 2026-07-26.
- One-time env->secretKeyRef migration executed against the cluster;
  README updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jasonwitty
2026-07-26 02:37:49 -07:00
parent 8afac39d03
commit 96e1825629
4 changed files with 165 additions and 13 deletions
+18 -13
View File
@@ -43,21 +43,26 @@ Three apps read secrets that are NOT in git. Each app dir has a
| `usp-license` | unified-streaming | `USP_LICENSE_KEY` |
| `searxng-1723974683-config` | default | searxng `settings.yml` |
**One-time migration (pihole + unified-streaming):** the live cluster (as of
2026-07-26) has WEBPASSWORD / USP_LICENSE_KEY as inline plaintext `value`s.
`kubectl apply` (client- or server-side) cannot patch an env var from `value`
to `valueFrom` — the API rejects the merged object. Validated procedure:
~~**One-time migration (pihole + unified-streaming)**~~ — DONE 2026-07-26:
secrets `pihole-admin` and `usp-license` created in-cluster and both
deployments switched to `secretKeyRef` via `kubectl replace` (a plain
`kubectl apply` cannot patch an env var from `value` to `valueFrom`).
`kubectl apply -k .` now converges cleanly (verified `--dry-run=server`).
```sh
# 1. create the two secrets (see secret.example.yaml in each app dir)
# 2. one-time replace (restarts the pods):
kubectl replace -f apps/pihole/deployment-pihole.yaml
kubectl replace -f apps/unified-streaming/deployment.yaml
```
## CI/CD (Gitea Actions)
After that, `kubectl apply -k .` works cleanly for everything (verified with
`--dry-run=server` against the live cluster, 2026-07-26 — zero immutable-field
conflicts).
`.gitea/workflows/deploy.yaml`, modeled on socktop-webterm's pipeline:
- **PRs** → `kubectl apply -k . --dry-run=server` (validation only)
- **push to main** → `kubectl apply -k .` + `kubectl rollout status` on all
seven deployments
Repo Actions secret required: `KUBECONFIG` — base64-encoded kubeconfig for the
`gitea-deployer` ServiceAccount (same identity socktop-webterm deploys with;
regenerate anytime from `default/gitea-deployer-token`). Its RBAC is
`rbac/gitea-deployer.yaml` — admin-applied once, deliberately outside the root
kustomization so the pipeline token cannot escalate itself; it has no access
to secrets and no delete verbs.
## Cluster assumptions (state that lives outside these manifests)