Chainguard
A Chainguard registry and platform API
Workloads reach cgr.dev and the Chainguard API by trading an OIDC token from any issuer you register (GitHub, GitLab, AWS, Kubernetes, CircleCI, your own) for a token valid up to an hour, matched on issuer, subject, audience and custom claims. Pull tokens remain for clients that cannot do OIDC and always expire within a year; the free Catalog Starter plan gets only those. Outbound, Chainguard signs its webhooks with OIDC and is the OIDC issuer for Checks into AWS, GCP and Azure.
Docs: edu.chainguard.dev · Checked 2026-10-22 · source YAML · dispute via PR
Inbound Arequires Paid plans (Catalog Starter organizations cannot create assumable identities)
How a workload running anywhere authenticates to this product.
Assumable identity: a Chainguard identity with a claim_match on issuer, subject, audience and custom claims (exact or regex), bound to a role. A workload presents its own OIDC token to issuer.enforce.dev/sts/exchange (or chainctl auth login --identity) and gets a Chainguard token valid up to an hour for the API and registry. Static pull tokens remain for clients that cannot run OIDC.
- Issuers
- any
- edu.chainguard.dev checked 2026-10-22
“You can restrict access to an identity so that only workflows that present tokens matching a specific issuer and subject can assume it.”
- edu.chainguard.dev checked 2026-10-22
“You must specify an issuer and subject in the claim match block, but you can optionally specify an `audience` here as well.”
- edu.chainguard.dev checked 2026-10-22
“you can exchange your platform's OIDC token for a Chainguard API token like in the following example.”
- edu.chainguard.dev checked 2026-10-22
“The API token issued by `/sts/exchange` will be valid for up to an hour.”
- edu.chainguard.dev checked 2026-10-22
“A pull token is the only credential they can issue for automation.”
- raw.githubusercontent.com checked 2026-10-22
“`claim_patterns` (Map of String) The custom claim patterns for matching acceptable custom claims that appear in tokens to assume this identity.”
- edu.chainguard.dev checked 2026-10-22
“First create an identity using `chainctl`, which can be limited to only allow OIDC federation from certain GitHub workflow runs:”
- edu.chainguard.dev checked 2026-10-22
“Tutorial outlining how to create a Chainguard identity that can be assumed by an AWS user or role using outbound identity federation.”
- edu.chainguard.dev checked 2026-10-22
“A Kubernetes cluster operates as an OIDC issuer.”
- edu.chainguard.dev checked 2026-10-22
“the identity will expire, with a maximum lifetime of 30d.”
- edu.chainguard.dev checked 2026-10-22
“This generates a longer-lived token that can be used to pull images from other environments that don't support OIDC, such as some CI environments, Kubernetes clusters, or with registry mirroring tools like Artifactory.”
- edu.chainguard.dev checked 2026-10-22
“Because ECR authenticates to Chainguard's registry on your behalf, you must supply it with credentials.”
Bring-your-own-issuer: any OIDC issuer can be named (exact or issuer_pattern), with exact or regex subject, audience and custom-claim matching; documented examples cover GitHub Actions, GitLab, Bitbucket, Buildkite, CircleCI, Jenkins, Keycloak, Entra ID, Kubernetes service account tokens and AWS IAM outbound identity federation (plus a legacy AWS GetCallerIdentity identity type). Issuers that are not reachable from the internet can register their JWKS as a "static" identity, capped at 30 days. The same exchanged token works for the control-plane API (console-api.enforce.dev), Terraform and cgr.dev, so no API function requires a static secret; per the weakest-path rule this keeps A. Pull tokens are still the documented path for clients that cannot run a token exchange (kubelet imagePullSecrets, ECR pull-through cache in Secrets Manager, Artifactory, Nexus, Cloudsmith mirrors). That is a limitation of those clients, not of Chainguard's API, but it means many real registry-mirror setups hold a static pull token; the hygiene below grades it. Tier gate: the free Catalog Starter plan cannot create assumable identities, so on that plan inbound is pull-token only (would be D).
Outbound A
How this product reaches into your cloud, repos, or other SaaS.
Chainguard reaches customer systems as an OIDC issuer or GitHub App, never with a customer secret: CloudEvents webhooks carry an issuer.enforce.dev OIDC token for the receiver to verify; Chainguard Checks gets short-lived AWS, GCP and Azure credentials through IAM OIDC providers, workload identity pools and Entra federated credentials that trust issuer.enforce.dev; Guardener and Checks act on GitHub through the Chainguard GitHub App.
- edu.chainguard.dev checked 2026-10-22
“Every Chainguard event has a JSON Web Token (JWT) formatted OIDC ID token in its Authorization header.”
- edu.chainguard.dev checked 2026-10-22
“Use the `iss` field to ensure that the issuer is Chainguard, specifically `https://issuer.enforce.dev`.”
- edu.chainguard.dev checked 2026-10-22
“It also sets up a Chainguard Identity with permissions to pull from the private `cgr.dev` repository, allows the Cloud Run service's service account to assume the puller identity, and sets up a subscription to notify the Cloud Run service when pushes happen to `cgr.dev`.”
- edu.chainguard.dev checked 2026-10-22
“A check's VM holds no long-lived credentials.”
- edu.chainguard.dev checked 2026-10-22
“In IAM, add an OpenID Connect identity provider with the provider URL `https://issuer.enforce.dev` and an audience, such as `sts.amazonaws.com`.”
- edu.chainguard.dev checked 2026-10-22
“For Google Cloud, add an OIDC provider to a workload identity pool, with the issuer `https://issuer.enforce.dev` and the attribute mapping `google.subject=assertion.sub`.”
- edu.chainguard.dev checked 2026-10-22
“In the Microsoft Entra application that the check signs in as, add a federated identity credential with the issuer `https://issuer.enforce.dev`, the subject `chainguard:<repository-id>:<identity>`, and an audience, such as `api://AzureADTokenExchange`.”
- edu.chainguard.dev checked 2026-10-22
“The bridge between the two is a **connection**: a Chainguard App installation on a GitHub organization, linked to a Chainguard organization.”
- edu.chainguard.dev checked 2026-10-22
“Set AWS account association for a location.”
Checked: CloudEvents subscriptions (registry push/pull and IAM events to a webhook you run; Chainguard signs each delivery with an OIDC JWT, so the receiver holds no shared secret); the image-mirroring examples (copy to Artifact Registry/ECR are customer-run services triggered by events, which pull from cgr.dev with an assumable identity and push with their own cloud identity; Chainguard never holds registry credentials); registry pull-through guides for ECR, Artifact Registry, Artifactory, Nexus, Harbor and Cloudsmith (all pull direction, so the pull token they store is an inbound credential, covered above); Chainguard Checks workload identities into AWS, GCP, Azure (keyless, Chainguard as OIDC issuer, trust pinned on the exact subject); Guardener and Checks via the Chainguard GitHub App; account associations for AWS, GCP and Azure (account ID, project, tenant/client IDs only, no secret; little current documentation of what uses them). Chainguard Workspaces sessions forward the developer's own laptop credentials (gcloud ADC, GitHub, Claude) and are human dev environments, not graded here. No integration found that asks for a static cloud key.
Hygiene for any static credential the product still issues
| ✓ Expiry enforceable | Pull tokens default to 30 days and the platform caps them at one year, so a never-expiring pull token cannot exist (a platform-enforced max lifetime passes, as on temporal). Static-JWKS identities are capped at 30 days. No org policy for a shorter cap is documented. The Console's "Custom" expiration date picker was not verified to enforce the same cap.
|
| ✓ Rotation via API | Pull tokens are created with chainctl auth pull-token create and revoked by deleting their identity (chainctl iam identities delete, or the /iam/v1/identities/{id} API), all scriptable from an assumable identity. On Catalog Starter the limited_owner role cannot delete identities; you delete the token's role binding instead.
|
| ✓ Scoped keys | Each pull token is its own machine identity limited to pulling one repository type, under an organization or folder you choose (--parent), not a copy of the creator's access.
|
| ✗ Last-used visible | The Identity API object carries lastSeen ("last federated"), but nothing documents whether a registry login with a pull token updates it, and the Console's Access Tokens list shows no last-used column. Judged a fail as not publicly verifiable; a documented last-used for pull tokens would flip it.
|
| ✗ Leak revocation | Chainguard does not appear in GitHub's supported secret scanning patterns table, so a leaked pull token is not reported to Chainguard for revocation.
|
Notes
One card for the Chainguard platform: the registry (cgr.dev, apk.cgr.dev, Libraries indexes) and the console-api.enforce.dev control plane share one IAM model and one STS. Checks, Guardener and Workspaces are newer products on the same IAM; they appear only in outbound. Inbound is A on paid plans and would be D on Catalog Starter (pull tokens only, three of five hygiene checks pass). Hygiene applies to pull tokens. A documented last-used timestamp and GitHub partner revocation for pull tokens would complete hygiene; the grades would not change.
Badge
[](https://wif.tax/p/chainguard-platform/)