zot v2.1.17: The OCI Registry That Just Learned to Think for Itself

| |

5 min read

zot logo

If you run a container registry, you already know the feeling. You stare at your artifact storage, think about authentication, authorization, signing, and observability, and realize you are stitching together five different tools just to push and pull images safely. That is exactly the problem zot solves. Zot is a production-grade, OCI-compliant container registry built in Go. It stores your container images, Helm charts, and OCI artifacts without requiring a separate database or cloud storage backend. Everything runs in a single binary. Teams that need a lightweight, self-hosted registry — whether for air-gapped environments, edge deployments, or just keeping things simple — are the ones reaching for zot.

Version 2.1.17 just landed, and it is one of the most feature-packed patch releases the project has shipped. The headline? Conditional access control powered by CEL expressions, a major maturity leap for the auth story. But there is more: OIDC session management finally gets proper logout, OpenID group claims let you map identity provider groups straight to registry permissions, Cosign bundle support strengthens the supply-chain security story, Prometheus gets garbage collection metrics, and the CLI got a complete configuration overhaul. Let us walk through the good stuff.

What Is New

Conditional Access Control with CEL Expressions

This is the big one. Zot now supports conditional access control via Common Expression Language (CEL), and it changes how you think about registry authorization. Instead of static RBAC rules that apply uniformly, you can write CEL expressions that evaluate dynamically against the request context — the user, the repository, the action, the image tags.

Why does this matter? If you run a multi-tenant registry, you have probably hit the wall where simple “allow/deny” rules are not enough. You want policies like “developers can push to repos matching their team name, but only during business hours” or “pull-only access for CI service accounts on production images.” CEL makes that possible without writing custom middleware.

If your registry authorization is still just a flat list of “who can do what,” CEL-based conditional access control is the upgrade that makes you wonder how you ever managed without it.

// Example CEL-based access policy
{
  "name": "team-push-access",
  "condition": "request.identity.groups.exists(g, g == request.repository.prefix)",
  "actions": ["push", "pull"]
}

PR #4040 — feat(authz): introduce conditional access control via CEL

OIDC Session Management Gets Real

Two new OIDC features land in this release, and together they close a gap that has annoyed anyone running zot behind a corporate identity provider.

RP-Initiated Logout means zot now properly supports the OpenID Connect logout flow. When a user logs out of your SSO provider, zot terminates the session cleanly instead of leaving stale tokens around. No more “I logged out but my session is still active” surprises.

OpenID groups claim mapping lets zot read the groups claim from your ID token and map those groups directly to registry access policies. If your Okta, Entra ID, or Keycloak setup already defines “platform-team” and “security-team” groups, zot can use those straight away — no manual group syncing needed.

// OIDC groups claim mapping in config
"openid": {
  "providers": {
    "keycloak": {
      "clientid": "zot-registry",
      "issuer": "https://sso.example.com/realms/platform",
      "scopes": ["openid", "profile", "email", "groups"]
    }
  }
}

PR #3975 — feat(auth): support OIDC RP-Initiated Logout

PR #3999 — feat(auth): map OpenID groups claim

Cosign Bundle Support

Supply-chain security is not optional anymore, and zot just made it easier. Cosign bundle support means zot can now store and serve Cosign verification bundles — the cryptographic proof that an image was signed by a trusted party. If you are running Sigstore Cosign to sign your container images, zot now natively handles the bundle artifacts alongside the images themselves.

This is one of those features that sounds incremental until you realize what it unlocks: a complete signing and verification pipeline that lives entirely inside your registry, no external storage needed.

PR #4023 — feat(cosign): add support for cosign bundle

Prometheus GC Metrics and Observability Upgrades

Running a registry in production means caring about garbage collection. Blobs accumulate, unreferenced layers pile up, and if you cannot see what is happening, disk usage creeps up silently. Prometheus GC metrics are now exposed so you can monitor exactly when garbage collection runs, how long it takes, and how many blobs it reclaims. Point your Grafana dashboard at the new metrics and stop guessing.

On top of that, zot now logs session and audit subjects from UserAccessControl, giving you a proper trail of who did what. Compliance teams will appreciate this one.

PR #3863 — feat(metrics): add Prometheus GC metrics

PR #4029 — feat(api): log session/audit subject from UserAccessControl

Multipart Range Blob Pulls

Pulling large container images over slow networks is painful. Zot now supports multipart range requests for blob pulls, meaning clients can request multiple byte ranges of a layer in a single HTTP request. Combined with the multipart download enhancements, this reduces round trips and improves pull performance, especially for large layers over high-latency connections.

PR #3995 — Support multipart range blob pulls

PR #4021 — Multipart download enhancements

zli Config Overhaul

The zot CLI, zli, got a complete configuration makeover. Instead of the old ad-hoc config approach, zli now has a typed configuration layer with strict validation and proper subcommands: list, show, get, set, and reset. Deprecated syntax is isolated and documented. Managing multiple registry endpoints just got a lot less error-prone.

PR #4037 — feat(zli): add config list/show/get/set/reset

PR #4030 — refactor(zli): add typed config layer and strict validation

Notable Fixes

  • Docker Compose and Buildx compatibility: zot now recognizes the Docker Compose and Buildx User-Agent strings in the v2 authentication challenge workaround. If you have been hitting auth failures with docker compose push, this fix is for you. PR #3992
  • Security hardening: Timeout configurations and body size limits have been enhanced to prevent abuse vectors. PR #3984
  • Sync tag filter fix: Tag filters are now applied before destination mapping, preventing images from being synced to the wrong location. PR #4003
  • Dependabot alerts resolved across multiple PRs (PR #3990, PR #4020, PR #4048, PR #4059, PR #4072)

That is a release. CEL-based authorization, proper OIDC session handling, Cosign bundles, Prometheus GC metrics, and a CLI that finally has a config system worth using. Zot v2.1.17 is not a patch release that quietly fixes things in the background — it pushes the project forward on auth, security, observability, and performance all at once. If you are running a self-hosted registry, this is the one to upgrade to.

Learn More