- Published on
Container Registries in 2026 — Docker Hub / GHCR / ECR / Harbor / Quay / Zot / Cosign + Sigstore Deep Dive
- Authors

- Name
- Youngju Kim
- @fjvbn20031
Prologue — The Registry Is Not an Image Warehouse
Back in 2015, container registries were simple. docker push was the whole story. Docker Hub was effectively the only choice, and self-hosting meant spinning up a single registry:2 container.
The 2026 landscape looks different.
- Docker Hub pricing has tightened — push/pull limits on free orgs nudged OSS projects to migrate to GHCR in droves.
- GHCR has effectively become the default for OSS containers. It is one and the same with GitHub Actions, public images are free, and authentication is a single
GITHUB_TOKEN. - ECR Public has become the free Quay alternative — global distribution from a single AWS account.
- Harbor has become the self-hosting standard as a CNCF graduated project. Almost every on-prem registry on top of Kubernetes is Harbor.
- Zot rose to CNCF incubation and now owns the emerging OCI-only simplicity niche.
- Cosign + Sigstore is the de facto signing standard, the default tool for SLSA Level 3 builds.
- ORAS has made everything other than container images — Helm charts, WASM modules, ML models, Terraform modules — storable as OCI artifacts.
- SBOMs (CycloneDX, SPDX) are attached at the registry, so you know what is inside the moment you pull the image.
The registry is no longer an image store. It is the central hub of supply-chain security. Who built it, what is in it, where it was verified — all live with the manifest, in the registry.
This post compares 13 registries, signing tools, and SBOM standards in one breath. Not a feature table, but the story of why a particular team picked a particular thing.
Chapter 1 · The 2026 Container Registry Map — Three Camps: Managed / Self-Hosted / Free OSS
Start with a map.
[Container Registries 2026]
|
+---------------------+---------------------+
| | |
[Managed SaaS] [Self-Hosted OSS] [Free OSS Hosting]
| | |
- Docker Hub - Harbor (CNCF) - GHCR (public free)
- GHCR (private paid) - Zot (CNCF) - ECR Public
- GitLab Registry - Distribution - Quay.io (OSS free)
- AWS ECR - Artifactory CE - Docker Hub (public)
- Google AR - Nexus
- Azure ACR
- Quay.io (Red Hat)
- Artifactory (JFrog)
The three camps differ along simple axes.
- Managed SaaS — cloud vendor runs it, you pay the invoice. Vendor owns availability. Trade-off: cost and multi-cloud portability.
- Self-hosted OSS — you run it, infra cost only. You own availability and security. Trade-off: operational burden.
- Free OSS hosting — OSS projects get free hosting for public repos. Private repos cost or have quotas.
The new flow in 2026 is that these three no longer separate cleanly.
- GitHub Actions builds an image, pushes to GHCR, mirrors to ECR, and hooks into Harbor as a pull-through proxy cache.
- After the Docker Hub pricing changes, OSS projects moved to GHCR and Quay.io, but user
docker pullcalls still land at Docker Hub — official images likelibrary/nginxlive there. - Enterprises stack Harbor on top of Artifactory, or run ACR as primary with ECR as mirror.
The registry is no longer a single choice but a multi-registry topology to design.
One line to remember: "In 2026 the registry choice is not a single pick — it is the design of a multi-registry topology."
Chapter 2 · Docker Hub — The Original, After the Pricing Shift
Docker Hub is the original container registry. docker pull nginx lands there by default, and it remains the canonical source of Official Images.
Where Docker Hub Stands in 2026
- Still the default destination for public images — verified collections under
library/,bitnami/,library/pythonand friends live here. - The Official Images program is still strong — image sets built and signed by Docker itself.
- Pricing has shifted several times. Free Team pull/push limits, free organization image retention, automatic deletion of inactive images — all have been applied or reversed at various times.
Impact of the Pricing Changes
- The 2023 free-org change announcement triggered OSS community pushback, partial rollback, and gradual subsequent tightening.
- Free authenticated pulls are roughly 100 images/hour (authenticated) and 200 images/hour (authenticated free). Unauthenticated is IP-based.
- Free orgs still get unlimited public repos, but private repo counts and automatic builds are limited.
- Result: OSS projects spread across GHCR, Quay.io, and ECR Public. Docker Hub remains the "default destination" but not the "only destination".
Why Docker Hub Still Matters
- Discoverability — the first place people look. Brand recognition.
- Official Images — a vetted catalog built over years.
- Docker Desktop integration —
docker loginand push. - Automated builds — GitHub/GitLab-linked builds.
Basic docker push Flow
# 1. Log in
docker login docker.io
# Username, Password (or PAT)
# 2. Tag
docker tag myapp:latest myorg/myapp:v1.0.0
# 3. Push
docker push myorg/myapp:v1.0.0
# 4. Pull (from elsewhere)
docker pull myorg/myapp:v1.0.0
The Rise of Pull-Through Cache
To reduce registry hops, many teams place a Harbor or Zot in front of Docker Hub as a pull-through cache. The first pull goes to Docker Hub and is cached internally; subsequent pulls do not touch Docker Hub at all, so its rate limit is irrelevant.
# Harbor config — Docker Hub proxy
proxy:
remote_url: https://registry-1.docker.io
username: ""
password: ""
Where Docker Hub Lands
The era of being the single source of free OSS is over. But it remains "the place you cannot ignore when you want public images discovered by people". The 2026 pattern is often: build and push to GHCR, mirror to Docker Hub, list both in the README.
Chapter 3 · GitHub Container Registry (GHCR) — Best Friend of GH Actions
GHCR is the container side of GitHub Packages. After GA in 2021, by 2026 it has effectively become the OSS registry standard.
GHCR Strengths
- One with GitHub Actions — push with
GITHUB_TOKEN, no separate credentials. Federate via OIDC to external infra. - Free for public images — unlimited storage and transfer.
- Repository permissions inherited automatically — if you can access the code repo, you can pull the image.
- Full OCI 1.1 support — Cosign signatures, SBOM attachments, multi-arch all work naturally.
Standard Push Pattern from Actions
# .github/workflows/build.yml
name: build-and-push
on:
push:
branches: [main]
permissions:
contents: read
packages: write
id-token: write # for OIDC
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: $GITHUB_ACTOR
password: $GITHUB_TOKEN
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/myorg/myapp:latest
platforms: linux/amd64,linux/arm64
ghcr.io/owner/image Naming
GHCR image paths follow a fixed pattern:
ghcr.io/USERNAME/IMAGE_NAME(personal account)ghcr.io/ORG_NAME/IMAGE_NAME(organization account)
This simplicity is powerful. Anyone who did git clone github.com/foo/bar knows how to docker pull ghcr.io/foo/bar.
Pricing for Private Images
- Private images count against your GitHub plan.
- Storage and data transfer are billed with free quotas per plan.
- Over-quota usage is billed per GB-month.
GHCR Limitations
- Pull performance — comparable to Docker Hub, but depends on Cloudflare cache for traffic spikes.
- No self-hosted version — managed only.
- Tag immutability — repository-wide only, fine-grained policies are missing.
Standard OSS Migration Path
The standard migration from Docker Hub to GHCR for OSS projects:
- Multi-arch build via GitHub Actions.
- Push to
ghcr.io/owner/project:tag. - Update README to lead with the GHCR pull command.
- Also mirror to Docker Hub (dual listing).
- Attach signatures with Cosign keyless.
One line to remember: "GHCR is the de facto standard for OSS that uses GitHub Actions. One line of build credentials and you push."
Chapter 4 · GitLab Container Registry
GitLab ships its container registry as a built-in feature of every GitLab project.
GitLab Registry Strengths
- Automatic per-project isolation —
registry.gitlab.com/group/project/image:tagis just the path. - Deep CI/CD integration —
$CI_REGISTRY,$CI_REGISTRY_USER,$CI_REGISTRY_PASSWORDare auto-injected. - Cleanup policy — GUI-configurable per project retention.
- Same on self-managed GitLab — install GitLab CE on-prem and the registry comes with it.
Standard .gitlab-ci.yml Push Pattern
build:
image: docker:24.0.5
services:
- docker:24.0.5-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
Dependency Proxy
GitLab builds in a Docker Hub pull-through proxy at the group level.
# Pull nginx from Docker Hub via GitLab proxy
docker pull gitlab.com/myorg/dependency_proxy/containers/nginx:latest
GitLab group authentication bypasses the Docker Hub rate limit.
Cleanup Policy
# Project settings > Packages and registries > Container Registry
# Cleanup policy (configurable via UI, API, or Terraform)
keep_n_tags_older_than: 1d
older_than: 30d
name_regex_keep: "release-.*"
name_regex_delete: ".*"
A simple policy engine that covers about 90% of use cases.
Where GitLab Registry Lands
The natural choice for teams already on GitLab. CI and permissions stay in one place. Self-managed gives you the same experience. Discoverability outside of GitLab users is lower than GHCR, though.
Chapter 5 · AWS ECR + ECR Public — The Free Quay Alternative
ECR (Elastic Container Registry) is AWS's private container registry. ECR Public was added in 2020, extending coverage to public artifacts.
ECR Strengths
- IAM integration — fine-grained auth via IAM role/policy. IRSA (IAM Roles for Service Accounts) injects credentials into EKS pods.
- Cross-region replication — automatic replication across regions.
- Built-in image scanning — Amazon Inspector integration, automatic CVE scans.
- Pull-through cache — cache from Docker Hub, GHCR, Quay, and mcr.microsoft.com.
- Lifecycle policy — retention policy via JSON DSL.
aws ecr get-login-password Flow
# 1. Login (12-hour token)
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
# 2. Create repository (auto-create also possible)
aws ecr create-repository --repository-name myapp
# 3. Push
docker tag myapp:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:v1
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:v1
Lifecycle Policy Example
{
"rules": [
{
"rulePriority": 1,
"description": "Keep last 10 production images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["prod-"],
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "Expire untagged after 7 days",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": { "type": "expire" }
}
]
}
ECR Public — Free OSS Hosting
public.ecr.aws/ lets you host OSS images globally and for free with just an AWS account.
- Free storage (50 GB/repo recommended cap).
- Free data transfer (anonymous pulls included).
- Separate domain (e.g.,
public.ecr.aws/aws/amazonlinux:2023).
OSS projects commonly add ECR Public as a destination to dodge Docker Hub rate limits and avoid GHCR private costs.
ECR Limitations
- AWS lock-in — multi-cloud workloads need separate pushes.
- Request-based pricing — pulls may be billed (public is free).
- Console-only UI — no full GUI like Harbor or GitLab.
Where ECR Lands
The default for teams running EKS, ECS, or Lambda on AWS. IRSA integration is overwhelmingly clean. For OSS, keep ECR Public as a secondary destination.
Chapter 6 · Google Artifact Registry — Successor to GCR
Google Artifact Registry (AR) is the official successor to Google Container Registry (GCR). GCR (gcr.io) is deprecated, with strong recommendations to migrate to Artifact Registry.
Why AR Replaced GCR
- Multi-format — beyond containers: Maven, npm, Python, Go, Helm, Debian, RPM, Apt all in one registry.
- VPC Service Controls — network perimeter policies.
- CMEK (Customer-Managed Encryption Keys) — fine encryption control.
- Regional/Multi-regional repos — finer regional choice than GCR.
- Fine-grained IAM — repo-level permission separation.
Migrating from GCR
# Migrate existing gcr.io images to AR
gcloud artifacts docker upgrade migrate \
--projects=my-project
# Create new AR repo
gcloud artifacts repositories create myrepo \
--repository-format=docker \
--location=us-central1 \
--description="Docker repo"
# Configure auth helper
gcloud auth configure-docker us-central1-docker.pkg.dev
# Push
docker tag myapp:latest \
us-central1-docker.pkg.dev/my-project/myrepo/myapp:v1
docker push us-central1-docker.pkg.dev/my-project/myrepo/myapp:v1
GKE Workload Identity Federation
# Kubernetes ServiceAccount -> GCP ServiceAccount mapping
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: default
annotations:
iam.gke.io/gcp-service-account: my-gcp-sa@my-project.iam.gserviceaccount.com
This lets GKE pods pull from AR without a separate secret.
AR Strengths
- Container Analysis integration — automatic vulnerability scanning.
- Binary Authorization — admission control allowing only signed images.
- Cosign support — keyless signatures attached to GAR.
- Remote/Virtual repo — Docker Hub pull-through proxy.
Where AR Lands
The natural choice for GCP users running GKE. Combined with Binary Authorization, you can enforce signature, vulnerability, and policy checks at admission in one motion.
Chapter 7 · Azure Container Registry (ACR)
ACR is Azure's managed container registry — the default source for every Azure container workload: AKS, App Service, Functions, Container Apps, and so on.
ACR Strengths
- Geo-replication — automatic global replication in the Premium tier, exposed through a single endpoint URL.
- ACR Tasks — registry-side builds (cloud-side builds).
- Content Trust (Notary v1) and Cosign both supported.
- Helm charts and OCI artifacts.
- Private link — completely private network access.
az acr login Flow
# 1. Login (uses Azure CLI credentials)
az acr login --name myregistry
# 2. Push to ACR repo
docker tag myapp:latest myregistry.azurecr.io/myapp:v1
docker push myregistry.azurecr.io/myapp:v1
# 3. Pull from AKS (Managed Identity)
# Use IAM integration instead of ImagePullSecret
ACR Tasks — Registry-Side Builds
# Auto-build on Git commit
az acr task create \
--name buildmyapp \
--registry myregistry \
--image myapp:$ID \
--context https://github.com/myorg/myapp.git \
--file Dockerfile \
--git-access-token $TOKEN
No separate build host needed. Buildah-based cloud-side build.
Retention Policy
az acr config retention update \
--registry myregistry \
--status enabled \
--days 30 \
--type UntaggedManifests
Korea / Japan Use
- KakaoPay uses Azure as one of its primary clouds and runs its internal images on ACR (based on public conference talks).
- Some Japanese game studios run Azure as primary and use ACR.
Where ACR Lands
The default for AKS and Azure DevOps teams. Geo-replication exposed through a single endpoint URL is operationally simpler than ECR.
Chapter 8 · Harbor (CNCF graduated) — The Self-Hosting Standard
Harbor was started at VMware and donated to CNCF. It graduated in 2020 and is the self-hosting standard in 2026.
Why Harbor Became the Self-Hosting Standard
- Full GUI — users, projects, permissions, policies, and replication all in the web UI.
- Project-level isolation — multi-tenancy.
- Vulnerability scanner integration — Trivy by default; Clair, Snyk, Anchore as plugins.
- Cosign and Notary support — signature verification integrated at admission.
- Replication policies — uni- or bi-directional replication to Docker Hub, GHCR, ECR, GAR, ACR, Quay, etc.
- Proxy cache — pull-through cache for external registries.
- Robot accounts — long-lived CI credentials with fine permission control.
Installing Harbor (Helm)
helm repo add harbor https://helm.goharbor.io
helm install harbor harbor/harbor \
--namespace harbor --create-namespace \
--set expose.type=ingress \
--set expose.ingress.hosts.core=harbor.example.com \
--set externalURL=https://harbor.example.com \
--set persistence.persistentVolumeClaim.registry.size=200Gi \
--set persistence.persistentVolumeClaim.chartmuseum.size=10Gi \
--set persistence.persistentVolumeClaim.trivy.size=20Gi
Typical Project / Robot / Replication Layout
[Harbor Project: production]
- Member: dev-team (Developer)
- Member: ops-team (Master)
- Robot: ci-build (push)
- Robot: ci-deploy (pull)
- Vulnerability Scanner: Trivy
- Cosign Signature: required (verified on deploy)
- Replication:
- to: ghcr.io/myorg (push, on push)
- from: docker.io/library/* (pull, on demand)
Pull-Through Proxy Cache
# Harbor Project = "dockerhub-proxy"
# External endpoint: https://registry-1.docker.io
# Cache TTL: 24h
# User usage:
# docker pull harbor.example.com/dockerhub-proxy/library/nginx:latest
# First pull goes through Docker Hub and is cached
# Subsequent pulls served from Harbor directly
That single pattern solves the Docker Hub rate limit.
Harbor Limitations
- Operational burden — Postgres, Redis, Trivy, Notary, Chartmuseum and more.
- Upgrade pain — major-version schema changes are not rare.
- Backup is your problem — image blobs and metadata both.
Where Harbor Lands
The default self-hosted container registry. GUI and replication are strong enough that non-developer ops teams can use it. Common in large on-prem deployments.
Chapter 9 · Quay (Red Hat / IBM)
Quay is the container registry that Red Hat acquired. Quay.io is the managed SaaS; Red Hat Quay is the self-hosted enterprise edition; Project Quay is the OSS upstream.
Quay Strengths
- One with OpenShift — the natural choice if you use OpenShift.
- Quay.io free for OSS — public repositories are free (especially in the Red Hat ecosystem).
- Free unlimited private repos for OSS orgs — granted to some OSS projects.
- Built-in Clair scanner — vulnerability scanner from the Quay team.
- Geo-replication — multi-region replication built in.
- Notary v2 and Cosign supported.
Quay Usage Pattern
# Quay.io
docker login quay.io
docker push quay.io/myorg/myapp:v1
# Self-managed Red Hat Quay
docker login quay.mycompany.com
docker push quay.mycompany.com/team/myapp:v1
Robot Account Model
Similar to Harbor. Issue long-lived tokens for CI, grant permissions at the repository level.
Where Quay Lands
- Default in the Red Hat ecosystem (OpenShift, RHEL).
- Splits the self-hosted enterprise space with Harbor.
- One of the free alternatives to Docker Hub for OSS hosting.
Chapter 10 · Zot (CNCF incubating) — OCI-Only Simplicity
Zot is an OCI-only container registry. It became a CNCF incubating project in 2024 and has emerged as the "small, simple, fast" self-hosting option.
Why Zot Rose as the Simplicity Pick
- Implements only the OCI distribution spec — no Docker registry v1, no proprietary extensions.
- Single binary — one Go file. No Postgres or Redis dependencies.
- Read-only mode — fits air-gapped environments.
- Sync — mirror from other registries.
- Metadata plugins — Cosign signature and SBOM search.
Running Zot
# Single binary
./zot serve config.json
# config.json
{
"storage": {
"rootDirectory": "/var/lib/zot"
},
"http": {
"address": "0.0.0.0",
"port": "5000"
},
"log": {
"level": "info"
},
"extensions": {
"search": { "enable": true },
"sync": {
"enable": true,
"registries": [
{
"urls": ["https://docker.io"],
"content": [{ "prefix": "library/nginx" }],
"onDemand": true
}
]
}
}
}
That is it. No Postgres, no Redis, no extra components.
Where Zot Lands
- Air-gapped environments — single binary, read-only mode.
- Edge and IoT — runs on small resources.
- Local dev registries — when Harbor is overkill.
- Throw-away registries pinned to a GitHub Actions runner — for unit tests.
One line to remember: "If Harbor is the full GUI all-in-one registry, Zot is the reference-implementation-level simplicity of the OCI distribution spec."
Chapter 11 · JFrog Artifactory — All-Languages Enterprise
Artifactory is JFrog's universal artifact registry. Beyond Docker containers, it covers Maven, Gradle, npm, NuGet, PyPI, CocoaPods, Conan, Cargo, Helm — every package manager in one place.
Artifactory Strengths
- All languages in one — no need to separate containers.
- Remote repos — pull-through cache for every external registry.
- Virtual repos — bundle multiple repos behind one endpoint.
- Build info tracking — graph relating builds to the artifacts they produce.
- JFrog Xray — vulnerability scanning, SBOM integration.
- JFrog Distribution — global distribution entry point.
- JFrog Pipelines — CI/CD integration.
Where Artifactory Lands
- Large enterprises — when non-container artifacts are heavy.
- Finance, telco, manufacturing — when Java and containers must coexist.
- License cost matters — Harbor is the fallback when pricing is too steep.
Artifactory CE — Community Edition
Only Docker is free. Full features require the paid license.
Chapter 12 · Distribution (CNCF) — The OCI Reference Implementation
Distribution is the OSS registry implementation Docker created. Donated to CNCF in 2018 and rebranded as Distribution, it serves as the reference implementation of the OCI distribution spec.
Where Distribution Lands
- The
registry:2container — the simplest in-house registry. - OCI spec reference — usually the first implementation when the spec changes.
- Base for other registries — Harbor, Zot, GHCR, etc. internally use Distribution or its forks.
Running Distribution
# Simplest single-node in-house registry
docker run -d -p 5000:5000 --restart=always \
-v /opt/registry-data:/var/lib/registry \
--name registry \
registry:2
# Usage
docker tag myapp:latest localhost:5000/myapp:v1
docker push localhost:5000/myapp:v1
Distribution Limitations
- No auth/permission model — implement basic auth or reverse proxy yourself.
- No UI — bring your own frontend.
- No scanner — integrate separate tooling.
Where Distribution Lands
- Single-node dev registries.
- Building block for other registries.
- For learning the OCI spec or auditing a reference implementation.
Most production deployments have moved to Harbor, Zot, or GHCR.
Chapter 13 · Sonatype Nexus
Nexus Repository is Sonatype's universal artifact registry. Same niche as Artifactory — every package manager plus Docker.
Nexus Strengths
- Nexus Repository OSS — free, with Docker proxy, host, and group support.
- De facto standard in the Maven ecosystem — Java-backend shops already have Nexus.
- Relatively light — simpler to operate than Artifactory.
- Nexus IQ Server — vulnerability, license, and policy checks.
Using Nexus
# After creating a hosted Docker repo in Nexus
docker login nexus.example.com:8082
docker push nexus.example.com:8082/myapp:v1
Where Nexus Lands
- Maven/Gradle teams already on Nexus — Docker fits in naturally.
- Free alternative to Artifactory.
- Container-specific features (scanner, replication) are weaker than Harbor.
Chapter 14 · Cosign + Sigstore — The Image Signing Standard
Sigstore is the non-profit project for OSS supply-chain security. Cosign is its container-image signing tool.
Sigstore Components
- Cosign — sign and verify CLI.
- Fulcio — short-lived CA (OIDC identity to X.509 cert).
- Rekor — append-only transparency log.
- TUF — root-of-trust distribution.
Keyless Signing — The 2026 Default
# 1. Sign without a key (using OIDC identity)
cosign sign ghcr.io/myorg/myapp:v1
# Browser opens to GitHub/Google/Microsoft OIDC login
# Fulcio issues a short-lived cert
# Rekor records the signature
# Cosign pushes cert + signature to the registry
# 2. Verify
cosign verify ghcr.io/myorg/myapp:v1 \
--certificate-identity=user@example.com \
--certificate-oidc-issuer=https://accounts.google.com
No key to carry around. The OIDC identity is the signer.
GitHub Actions Automatic Signing
permissions:
id-token: write # for OIDC token issuance
contents: read
packages: write
jobs:
build-and-sign:
runs-on: ubuntu-latest
steps:
- uses: docker/build-push-action@v5
id: build
with:
push: true
tags: ghcr.io/myorg/myapp:latest
- uses: sigstore/cosign-installer@v3
- run: cosign sign --yes ghcr.io/myorg/myapp@$DIGEST
env:
DIGEST: ${{ steps.build.outputs.digest }}
The GitHub Actions OIDC identity is embedded in the signature. Verifying with --certificate-identity-regexp=https://github.com/myorg/.* proves "built by this organization's GitHub Actions".
Admission Control Integration
# Kyverno policy example
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-cosign-signature
spec:
validationFailureAction: enforce
rules:
- name: verify-image
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "ghcr.io/myorg/*"
attestors:
- entries:
- keyless:
subject: "https://github.com/myorg/.*"
issuer: "https://token.actions.githubusercontent.com"
This single policy means only "images built by myorg's GitHub Actions" will be admitted to the cluster.
Where Cosign + Sigstore Lands
The de facto standard for container signing in 2026. Docker Content Trust (Notary v1) is effectively deprecated. Notary v2 is moving toward OCI spec standardization. In practice, Cosign is the most widely used.
Chapter 15 · in-toto / SBOM (CycloneDX, SPDX) / Notary v2 — Supply-Chain Security
Signing alone is not enough. On top of "who built this image" you need "what is inside this image" and "what process produced this image".
in-toto — Supply-Chain Attestations
in-toto is a framework for producing attestations for each step of the build pipeline.
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [{
"name": "ghcr.io/myorg/myapp",
"digest": { "sha256": "abc123..." }
}],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": {
"buildType": "https://github.com/Attestations/GitHubActions/v1",
"externalParameters": {
"workflow": ".github/workflows/build.yml",
"ref": "refs/heads/main"
}
},
"runDetails": {
"builder": { "id": "https://github.com/actions/runner@v2.319.0" },
"metadata": {
"invocationId": "https://github.com/myorg/myapp/actions/runs/12345"
}
}
}
}
Core building block for SLSA (Supply-chain Levels for Software Artifacts) Level 3 builds.
SBOM — Software Bill of Materials
A list of every dependency inside an image.
CycloneDX
OWASP's SBOM standard.
# Generate SBOM with Syft (CycloneDX format)
syft ghcr.io/myorg/myapp:v1 -o cyclonedx-json > sbom.cdx.json
# Attach to image (Cosign)
cosign attach sbom --sbom sbom.cdx.json \
--type cyclonedx ghcr.io/myorg/myapp:v1
SPDX
The Linux Foundation's SBOM standard.
syft ghcr.io/myorg/myapp:v1 -o spdx-json > sbom.spdx.json
cosign attach sbom --sbom sbom.spdx.json \
--type spdx ghcr.io/myorg/myapp:v1
Both formats are ISO-standardized. Tool compatibility is fine either way. CycloneDX is stronger on vulnerability integration; SPDX is stronger on license tracking.
Notary v2 — OCI Signing Standard
Notary v1 (Docker Content Trust) is effectively deprecated. Notary v2 standardizes signing on top of the OCI artifact spec.
- Built on the OCI artifact spec — signatures stored as separate manifests.
- Default support in ACR and Quay — sign and verify via the
notationCLI. - Coexists with Cosign — Cosign is registered as an alternate signer in the Notary v2 spec.
# Notation CLI (Notary v2 reference impl)
notation sign --plugin azure-kv \
--id "https://myvault.vault.azure.net/keys/mykey/abc123" \
myregistry.azurecr.io/myapp:v1
notation verify \
--signature myregistry.azurecr.io/myapp:v1
Where in-toto / SBOM / Notary v2 Land
- in-toto — attestations for SLSA Level 3 builds. Practically required for SLSA L3.
- SBOM — required for regulatory compliance (EO 14028, EU CRA).
- Notary v2 — adoption centered on ACR and Quay. Cosign is more widely used, but ecosystem distribution is comparable.
One line to remember: "In 2026 supply-chain security is a package of three: signing (Cosign) + attestation (in-toto) + bill of materials (SBOM)."
Chapter 16 · ORAS — Generic OCI Artifacts
ORAS (OCI Registry As Storage) is the tool for storing everything other than container images — Helm charts, WASM modules, ML models, Terraform modules, OPA bundles — as OCI artifacts.
ORAS Motivation
The OCI distribution spec can store arbitrary artifacts, not just images. The missing piece was client tooling. ORAS fills that gap.
# Push an arbitrary file as an OCI artifact
oras push ghcr.io/myorg/wasm-modules:v1 \
./module.wasm:application/wasm
# Pull
oras pull ghcr.io/myorg/wasm-modules:v1
# Inspect manifest
oras manifest fetch ghcr.io/myorg/wasm-modules:v1
ORAS Use Cases
- Helm charts —
helm push my-chart-1.0.0.tgz oci://registry.example.com/charts - WASM modules — wasmCloud and Krustlet pull modules from OCI registries.
- ML models — KServe and ModelMesh distribute models as OCI artifacts.
- OPA bundles, Cosign signatures, SBOMs — already OCI artifacts.
Where ORAS Lands
The force behind container registries evolving into universal artifact registries. Center of the wave moving Helm, WASM, ML models, and more onto OCI registries.
Chapter 17 · Korea / Japan — Toss, KakaoPay, Mercari, LINE
Korea
- Toss runs an internal proprietary registry (an in-house tool with Harbor underneath), also used as a pull-through proxy for OSS images. Internal dev conference talks have shared the structure where build pipelines push to the internal registry.
- KakaoPay uses Azure as one of its main clouds and runs ACR as the core container registry (based on public internal tech blogs).
- Naver / LINE Korea combine multi-cloud (including NCP) with internal registries.
- Korean OSS projects are increasingly GHCR-first with Docker Hub mirroring as a pattern.
Japan
- Mercari runs a multi-cloud build pipeline centered on GitHub Actions and GHCR. Some workloads go directly to GCP Artifact Registry.
- LINE runs an in-house container platform with its own registry. A Harbor-based structure has been mentioned in internal conference talks.
- CyberAgent / DeNA mix GKE and EKS, GAR and ECR.
- Japanese OSS projects commonly dual-publish to GHCR and Docker Hub.
Common Korea / Japan Patterns
- The internal core infra is self-hosted (Harbor) or managed (ACR/ECR/GAR) with external mirror to GHCR.
- OSS builds are de facto GitHub Actions + GHCR + Cosign keyless.
- Docker Hub is the "secondary public exposure destination".
Chapter 18 · Who Should Pick What — OSS / Startup / Enterprise / Air-Gapped
OSS Projects — GHCR
- Free build (Actions), free storage (public).
- Cosign keyless signing auto via OIDC.
- One line in README:
ghcr.io/org/project. - Optionally mirror to Docker Hub for user visibility.
Startups — Primary Cloud Managed + GHCR
- ECR on AWS, GAR on GCP, ACR on Azure.
- GitHub Actions to GHCR, then mirror to the primary cloud registry.
- Minimize ops burden.
Mid-Size Companies — Harbor + Primary Cloud
- One Harbor on-prem, one managed cloud registry.
- Pull-through proxy bypasses Docker Hub rate limits.
- Cosign + Trivy for admission control.
Large Enterprises — Artifactory or Harbor + Multi-Cloud
- Artifactory if non-container artifacts (Maven, npm) are heavy.
- Harbor + managed clouds if containers dominate.
- Full stack with Cosign + Notary v2 + SBOM + in-toto attestations.
Air-Gapped / Government / Regulated Finance — Zot or Harbor Offline
- Zot's read-only mode + single binary is strong for air-gapped.
- Harbor offline installer with replication for sync.
- Sync SBOMs and Cosign signatures into the air-gapped side as well.
Decision Matrix
| Condition | Recommendation |
|---|---|
| OSS project | GHCR (+ Docker Hub mirror) |
| AWS-only | ECR (+ ECR Public for OSS) |
| GCP-only | Google Artifact Registry |
| Azure-only | ACR |
| Already on GitLab | GitLab Container Registry |
| Already on OpenShift | Red Hat Quay |
| Self-hosted, need full GUI | Harbor |
| Self-hosted, want simplicity | Zot |
| All languages + containers in one | Artifactory or Nexus |
| Air-gapped | Zot read-only or Harbor offline |
| Signing / verification | Cosign + Sigstore |
| Supply-chain attestation | in-toto + SLSA |
| Bill of materials | CycloneDX or SPDX |
| Store Helm / WASM / ML models | ORAS + OCI registry |
Epilogue — The Registry Is Already the Center of Supply-Chain Security
In 2026, container registries are no longer "places that store images".
- Images carry signatures (Cosign).
- Images carry bills of materials (SBOM).
- Images carry build attestations (in-toto).
- Images are mirrored across multiple registries (Harbor replication).
- Images are verified at admission (Kyverno, Binary Authorization).
- And everything beyond containers — Helm, WASM, ML models — lives on the same registries (ORAS).
The job is not to pick one registry. It is to design the central node of a supply-chain security topology.
Tool choice is not a simple feature table. It is a function of cloud choice, CI choice, operational capacity, and regulatory requirements. I hope this post helps you fix the inputs to that function.
The final line: The registry is not an endpoint, it is a starting point. The moment an image enters it, every link of the supply chain is verified from there.
References
- Docker Hub Documentation — https://docs.docker.com/docker-hub/
- Docker Hub Subscription Pricing — https://www.docker.com/pricing/
- GitHub Container Registry Docs — https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
- GHCR for Actions — https://docs.github.com/en/actions/publishing-packages/publishing-docker-images
- GitLab Container Registry — https://docs.gitlab.com/ee/user/packages/container_registry/
- GitLab Dependency Proxy — https://docs.gitlab.com/ee/user/packages/dependency_proxy/
- AWS ECR User Guide — https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html
- ECR Public Gallery — https://gallery.ecr.aws/
- ECR Lifecycle Policies — https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html
- Google Artifact Registry — https://cloud.google.com/artifact-registry/docs
- GAR Migration from GCR — https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr
- Binary Authorization — https://cloud.google.com/binary-authorization
- Azure Container Registry — https://learn.microsoft.com/en-us/azure/container-registry/
- ACR Tasks — https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tasks-overview
- Harbor Project — https://goharbor.io/
- Harbor Docs — https://goharbor.io/docs/
- CNCF Harbor Graduation Announcement — https://www.cncf.io/announcements/2020/06/23/cloud-native-computing-foundation-announces-harbor-graduation/
- Project Quay — https://www.projectquay.io/
- Red Hat Quay — https://www.redhat.com/en/technologies/cloud-computing/quay
- Zot Registry — https://zotregistry.dev/
- CNCF Zot Incubation — https://www.cncf.io/projects/zot/
- JFrog Artifactory — https://jfrog.com/artifactory/
- Sonatype Nexus Repository — https://www.sonatype.com/products/sonatype-nexus-repository
- CNCF Distribution — https://distribution.github.io/distribution/
- OCI Distribution Spec — https://github.com/opencontainers/distribution-spec
- OCI Image Spec — https://github.com/opencontainers/image-spec
- Sigstore — https://www.sigstore.dev/
- Cosign Docs — https://docs.sigstore.dev/cosign/
- Rekor Transparency Log — https://docs.sigstore.dev/rekor/overview
- Fulcio CA — https://docs.sigstore.dev/fulcio/overview
- in-toto — https://in-toto.io/
- in-toto attestations — https://github.com/in-toto/attestation
- SLSA Framework — https://slsa.dev/
- CycloneDX — https://cyclonedx.org/
- SPDX — https://spdx.dev/
- Syft (SBOM tool) — https://github.com/anchore/syft
- Notary Project (v2) — https://notaryproject.dev/
- ORAS Project — https://oras.land/
- Kyverno verifyImages — https://kyverno.io/docs/policy-types/verify-images/
- Trivy Scanner — https://trivy.dev/