blumeops/docs/how-to/zot/wire-ci-registry-auth.md
Erich Blume b42660f881 Fold enforce-tag-immutability into harden-zot-registry
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>
2026-02-21 07:52:49 -08:00

2.2 KiB

title modified status tags
Wire CI Registry Auth 2026-02-21 active
how-to
zot
ci
forgejo

Wire CI Registry Auth

Ensure both CI push paths authenticate to zot after auth is enabled.

Context

There are two push paths to update:

  1. Dagger path (.forgejo/workflows/build-container.yaml.dagger/src/blumeops_ci/main.py): Add with_registry_auth() to the Dagger publish() call, sourcing the API key from env var ZOT_CI_API_KEY.

  2. Nix/skopeo path (.forgejo/workflows/build-container-nix.yaml): Add --dest-creds to skopeo 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 requires dependency.

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)