Tag immutability requires auth to be meaningful, so it can't be resolved independently. Replace client-side push checks with server-side accessControl policy: artifact-workloads group gets read+create (no update/delete), enforcing immutability at the registry level. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2.2 KiB
| title | modified | status | tags | ||||
|---|---|---|---|---|---|---|---|
| Wire CI Registry Auth | 2026-02-21 | active |
|
Wire CI Registry Auth
Ensure both CI push paths authenticate to zot after auth is enabled.
Context
There are two push paths to update:
-
Dagger path (
.forgejo/workflows/build-container.yaml→.dagger/src/blumeops_ci/main.py): Addwith_registry_auth()to the Daggerpublish()call, sourcing the API key from env varZOT_CI_API_KEY. -
Nix/skopeo path (
.forgejo/workflows/build-container-nix.yaml): Add--dest-credstoskopeo copy, sourcing the API key from the same env var.
Note: The API key must be generated manually after OIDC login is working — log in to zot UI via browser, generate an API key, and store it in 1Password. This is a manual step between register-zot-oidc-client and this card, but not modeled as a formal
requiresdependency.
CI authenticates as a service account in the artifact-workloads group (created in register-zot-oidc-client). This group grants ["read", "create"] — CI can push new tags but cannot overwrite or delete existing ones, enforcing tag immutability server-side.
Secret Flow
Indri runner (minikube)
1Password item (new: zot-ci-apikey) → ExternalSecret in forgejo-runner namespace → env var ZOT_CI_API_KEY in runner pod
Ringtail runner (k3s)
1Password → /etc/forgejo-runner/zot-api-key.env (or similar) deployed by NixOS config
Key Files
| File | Purpose |
|---|---|
.dagger/src/blumeops_ci/main.py |
Add with_registry_auth() to publish |
.forgejo/workflows/build-container.yaml |
Pass ZOT_CI_API_KEY to Dagger |
.forgejo/workflows/build-container-nix.yaml |
Add --dest-creds to skopeo |
argocd/manifests/forgejo-runner/deployment.yaml |
Mount secret as env var |
argocd/manifests/forgejo-runner/external-secret.yaml |
Pull API key from 1Password |
nixos/ringtail/configuration.nix |
Ringtail runner secret provisioning |
Verification
- Dagger push succeeds with registry auth
- Nix/skopeo push succeeds with registry auth
- Push without credentials fails (401)
Related
- harden-zot-registry — Parent goal
- register-zot-oidc-client — OIDC client registration (do first)