## Summary - Enable OIDC + API key authentication on zot registry with three-tier accessControl - `anonymousPolicy: ["read"]` — anyone can pull - `artifact-workloads` group: `["read", "create"]` — CI push, no overwrite/delete - `admins` group: `["read", "create", "update", "delete"]` — break-glass - Wire both CI push paths (Dagger and Nix/skopeo) with `ZOT_CI_API_KEY` credentials - Add `artifact-workloads` PolicyBinding in Authentik blueprint for zot app access - Add `ZOT_CI_API_KEY` to Forgejo Actions secrets via existing ansible role Completes the `wire-ci-registry-auth` and `harden-zot-registry` Mikado cards. ## Manual Deployment Steps (after merge) 1. Deploy Authentik blueprint: `argocd app sync authentik` 2. In Authentik admin UI: set a password for the `zot-ci` service account 3. Deploy zot config: `mise run provision-indri -- --tags zot` 4. Log in to `https://registry.ops.eblu.me` as `zot-ci` via OIDC → generate API key 5. Store API key in 1Password as `zot-ci-apikey` in blumeops vault 6. Sync Forgejo secrets: `mise run provision-indri -- --tags forgejo_actions_secrets` 7. Trigger a test container build to verify CI push 8. Verify anonymous pull: `curl -sf https://registry.ops.eblu.me/v2/_catalog` ## Uncertainties - **Zot `accessControl` group matching with OIDC:** Groups from Authentik's `profile` scope claim should map to zot policy groups, but the exact claim-to-group matching needs runtime verification - **`http.auth.apikey: true`:** This config key is documented but needs verification against the specific zot version built from source on indri - **API key permissions:** Need to confirm zot API keys inherit the generating user's group for accessControl evaluation ## Test Plan - [ ] `mise run provision-indri -- --check --diff --tags zot` shows expected config changes - [ ] Anonymous pull works after deploy - [ ] Unauthenticated push fails (401) - [ ] OIDC browser login redirects to Authentik and back - [ ] API key push works after key generation - [ ] CI push succeeds with both Dagger and skopeo paths - [ ] `mise run services-check` passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/237
2.2 KiB
2.2 KiB
| title | modified | tags | ||
|---|---|---|---|---|
| Zot | 2026-02-07 |
|
Zot
OCI-native container registry providing pull-through cache and private image storage.
Quick Reference
| Property | Value |
|---|---|
| URL | https://registry.ops.eblu.me |
| Local Port | 5050 |
| Data | ~/zot |
| Config | ~/.config/zot/config.json |
| LaunchAgent | mcquack |
Namespace Convention
| Path | Source |
|---|---|
registry.ops.eblu.me/docker.io/* |
Cached from Docker Hub |
registry.ops.eblu.me/ghcr.io/* |
Cached from GHCR |
registry.ops.eblu.me/quay.io/* |
Cached from Quay |
registry.ops.eblu.me/blumeops/* |
Private images |
Pull-Through Cache
When cluster pulls an image, containerd checks zot first. If cached, returns immediately. If not, zot fetches from upstream, caches it, then returns.
Security Model
OIDC authentication via authentik, with API key support for CI. Three-tier access control:
| Role | Permissions | Use case |
|---|---|---|
| Anonymous | read | Pull images without auth |
artifact-workloads group |
read, create | CI push (new tags only, no overwrite/delete) |
admins group |
read, create, update, delete | Break-glass admin access |
CI authenticates with a zot API key generated from the zot-ci service account's OIDC session. The key is stored in the Forgejo Secrets 1Password item (field zot-ci-api) and synced to Forgejo Actions secrets via ansible.
API Key Rotation
The zot-ci API key expires every 90 days. To rotate:
- In Authentik admin UI, impersonate the
zot-ciuser - Visit
https://registry.ops.eblu.me— you'll land on the login page - Click "SIGN IN WITH OIDC" to authenticate as zot-ci
- Navigate to
https://registry.ops.eblu.me/user/apikey - Generate a new API key, copy it to clipboard
- Update 1Password:
pbpaste | op item edit "Forgejo Secrets" --vault blumeops "zot-ci-api[password]=-" - Sync to Forgejo:
mise run provision-indri -- --tags forgejo_actions_secrets