Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Registry Token Endpoint

Ahdapa can act as the authentication backend for a private OCI container registry (Harbor, Docker Distribution, GitLab’s built-in registry, or any registry supporting the OCI Distribution v2 Bearer token protocol). A CI pipeline authenticates once — with a static client credential, or passwordlessly by presenting an externally issued OIDC JWT (e.g. a GitHub Actions workload token) — and receives a short-lived, repository-scoped token to hand directly to docker login / docker push / docker pull. No long-lived registry password is stored anywhere.

This gives a private deployment the same “keyless CI” experience that Docker Hub’s OIDC connections and quay.io’s GitHub Actions federation provide for public registries.


How it works

  1. docker login/podman login (or the registry itself, via its own WWW-Authenticate: Bearer realm="..." challenge) calls GET /registry/token?service=<registry-host>&scope=repository:<name>:<actions>.
  2. Ahdapa authenticates the caller:
    • Static credential — HTTP Basic Auth with a registered client’s client_id/client_secret.
    • Passwordless JWT — HTTP Basic Auth with client_id and an externally issued OIDC JWT as the password, resolved via the same federation-policy mechanism documented in Federation and Token Exchange.
    • Anonymous — no Authorization header at all, permitted only for repositories matching [registry] anonymous_pull_repositories, and only ever for pull.
  3. For each requested repository/action pair, ahdapa checks two independent, both-must-pass gates:
    • The effective client’s allowed_registry_repositories grants (glob pattern → allowed actions).
    • If any live HBAC rule exists, the HBAC registry-repository/action dimension (see Identity HBAC Policy).
  4. Ahdapa mints a short-lived JWT (5 minutes) with an OCI-spec access claim listing only the repository/action pairs actually authorized — a partially- or fully-unauthorized request still gets 200 OK with a reduced (possibly empty) access list, per the OCI spec’s soft-denial model, not a hard failure.
  5. The registry (configured to trust ahdapa’s signing key / JWKS) accepts the token for the matched actions.

Manual configuration

[registry]
enabled = true
allowed_services = ["registry.example.com"]
anonymous_pull_repositories = ["myorg/public-*"]
  • allowed_services — the incoming service parameter must match one of these, or the request is refused with 401. This prevents ahdapa from being used as a token-minting oracle for an attacker-controlled registry hostname.
  • anonymous_pull_repositories — glob patterns eligible for unauthenticated, pull-only access. Empty by default (fully opt-in); push/delete can never be granted anonymously regardless of configuration.

Per-client repository grants are set via the admin API (or a static TOML client), not this config section — see Admin API — Client fields’s allowed_registry_repositories entry:

[[client]]
client_id     = "ci-runner"
client_name   = "CI Runner"
token_endpoint_auth_method = "client_secret_basic"
client_secret = "..."
grant_types   = ["urn:ietf:params:oauth:grant-type:token-exchange"]
allowed_registry_repositories = [
    { pattern = "myorg/*", actions = ["pull", "push"] },
]

See also