← DevOps← DevOps
DevOpsDevOps18 Th7, 2026Jul 18, 202617 phút đọc14 min read

Quản lý Artifact (Artifact Management)Artifact Management

Thuộc bộ tài liệu DevOps Roadmap.

Tổng quan

Artifact là bất kỳ file nào do quá trình build tạo ra mà bạn deploy, phân phối hoặc phụ thuộc vào: binary đã compile, package theo ngôn ngữ (JAR, wheel, npm tarball), container image, Helm chart, package hệ điều hành (deb/rpm), thậm chí cả model machine learning. Quản lý artifact là kỷ luật lưu trữ, đánh version, bảo mật và phân phối các sản phẩm build này thông qua repository chuyên dụng, thay vì chia sẻ file tùy tiện hay build lại từ source mỗi lần cần.

Trong một pipeline CI/CD lành mạnh, artifact được build đúng một lần, gán danh tính bất biến (immutable), rồi được promote qua các môi trường (dev → staging → prod) mà không thay đổi. Nguyên tắc “build once, deploy many” này là thứ làm cho deployment có thể tái lập và rollback trở nên đơn giản. Không có artifact repository, team sẽ build lại cho từng môi trường — nghĩa là thứ bạn đã test không thực sự là thứ bạn ship.

Quản lý artifact cũng đã trở thành tuyến đầu về bảo mật. Các cuộc tấn công chuỗi cung ứng (dependency confusion, typosquatting, registry bị xâm nhập) nhắm đúng vào tầng này — vì vậy thực hành hiện đại bổ sung provenance, ký số (Sigstore/cosign) và SBOM bên trên việc lưu trữ đơn thuần.

Tại sao cần repository chuyên dụng, chứ không chỉ Git hay file share

Một câu hỏi tự nhiên là “sao không commit artifact vào Git, hay bỏ lên storage chia sẻ?” Ba lý do khiến repository chuyên dụng trở thành chuẩn:

  1. Binary phá vỡ version control. Git sinh ra cho text diff được; blob binary lớn phình history không thể đảo ngược và làm clone chậm khủng khiếp. Artifact repository lưu binary hiệu quả với deduplication.
  2. Hiểu giao thức. Một repository thật nói đúng giao thức native — Maven, npm, PyPI, NuGet, OCI/Docker Registry v2 — nên công cụ sẵn có của bạn (mvn, npm, pip, docker pull) chạy y nguyên chỉ bằng cách trỏ tới một URL khác.
  3. Metadata, tìm kiếm và policy. Repository theo dõi ai publish gì, khi nào, từ build nào, đính kèm checksum và chữ ký, cưỡng chế retention, và trả lời “artifact nào chứa log4j 2.14?” — file share không làm được gì trong số này.

Mô hình tư duy: artifact repository là ranh giới giữa “code” và “hệ thống đang chạy”. Source chảy vào từ Git, được build thành artifact bất biến, và mọi deployment kéo từ repository. Nếu repository đáng tin và nội dung của nó bất biến và đã ký, bạn có thể suy luận về những gì đang chạy ở production. Nếu nó là chốn hỗn loạn tự do, bạn không thể.

Kiến thức nền tảng

Những gì được coi là artifact

LoạiVí dụĐịnh dạng/giao thức registry
Package theo ngôn ngữJAR/WAR, npm package, Python wheel, NuGet, Go module, Ruby gem, Cargo crateMaven, npm, PyPI, NuGet, Go proxy, crates.io
Container imageApp image, base imageOCI / Docker Registry v2
Package OS.deb, .rpm, apkAPT, YUM, repo Alpine
Gói triển khaiHelm chart, Terraform module, WASM moduleOCI, Helm repo, Terraform registry
Binary chungCLI tool, installer, firmware, model MLGeneric/raw repository

Một nhận ra hữu ích: OCI đã lặng lẽ trở thành định dạng artifact phổ quát. Vốn là spec cho container image, OCI registry nay lưu Helm chart, WASM module, SBOM, chữ ký và file tùy ý dưới dạng “OCI artifact”. Ngày càng nhiều, “push nó lên registry dưới dạng OCI artifact” là câu trả lời cho bất cứ thứ gì cần lưu trữ content-addressable, bất biến và phân phối được — không chỉ container image.

Vai trò của artifact repository

  1. Local/hosted repository — lưu artifact bạn build (package nội bộ, image nội bộ). Đây là source of truth cho artifact first-party.
  2. Proxy/remote repository — cache các registry công cộng (Maven Central, npmjs, Docker Hub, PyPI). Build vẫn chạy khi upstream sập hoặc bị rate-limit, tải nhanh hơn (cache local) và audit được, và bạn có một điểm chốt để scan và chặn package độc hại trước khi nó tới tay developer.
  3. Virtual/group repository — một URL duy nhất gộp hosted + proxy, để build tool chỉ cần trỏ về một endpoint. Thứ tự resolution quan trọng: thường internal-hosted được tìm trước public-proxy để kẻ tấn công không thể “che” tên package nội bộ (xem dependency confusion bên dưới).

Các trình quản lý artifact repository chính

Công cụMô hìnhĐiểm mạnh
JFrog ArtifactoryThương mại (self-hosted hoặc SaaS)Hỗ trợ nhiều định dạng nhất (30+), virtual repo, tính năng enterprise trưởng thành, Xray để scan bảo mật/license
Sonatype Nexus RepositoryOSS + thương mạiLựa chọn miễn phí phổ biến, hỗ trợ tốt Maven/npm/Docker, kết hợp Nexus IQ / Lifecycle cho policy và scan
GitHub PackagesSaaS, gắn với GitHubKhông cần setup cho team dùng GitHub; npm, Maven, NuGet, RubyGems, container (ghcr.io); tích hợp Actions chặt chẽ
GitLab Package/Container RegistryĐóng gói cùng GitLabTích hợp với GitLab CI; hỗ trợ hầu hết định dạng package và container image
HarborOpen source (CNCF)Registry container/OCI với RBAC, replication, tích hợp sẵn Trivy, ký cosign, robot account, quota
Docker HubSaaSRegistry image public mặc định; official & verified image; rate limit với pull ẩn danh/free
AWS ECR / Azure ACR / Google Artifact RegistryCloud-nativeTích hợp IAM, geo-replication, scanning, cưỡng chế immutable tag; GAR còn hỗ trợ cả package ngôn ngữ (npm/Maven/PyPI)
Cloudsmith / GemfurySaaSHost package đa định dạng có quản lý mà không phải tự chạy hạ tầng

Chọn giữa chúng, ngắn gọn: đi sâu vào một cloud → registry native (ECR/ACR/GAR) là đường ít trở ngại nhất. Trên GitHub/GitLab → registry đóng gói sẵn tiết kiệm setup. Cần một nơi cho 20 định dạng với policy enterprise → Artifactory hoặc Nexus. Muốn registry container self-hosted, thiên bảo mật → Harbor.

Vị trí của artifact trong pipeline

Build một lần, promote cùng một artifact
  1. 01Push code
  2. 02CI build
  3. 03test
  4. 04publish artifactv1.4.2 / sha256:…
  5. cùng một artifact, config khác nhau
    05deploy dev
  6. 06promote staging
  7. 07promote prod

Promote là thao tác trên metadata (retag, copy giữa các repo), không bao giờ là build lại. Config được inject lúc deploy (env var, config map, secret) để cùng một artifact bất biến hành xử đúng ở mỗi môi trường. Nếu bạn thấy mình truyền giá trị đặc thù môi trường vào lúc build, bạn đã phá vỡ build-once-deploy-many và không còn tin được rằng staging đã test đúng thứ production chạy.

Khái niệm chính

Chiến lược versioning

# Build với tag bất biến, truy vết được
docker build -t registry.example.com/team/api:1.4.2-gitsha.9f8e7d6 .
docker push registry.example.com/team/api:1.4.2-gitsha.9f8e7d6

# Deploy pin theo content digest (không thể bị thay đổi âm thầm)
image: registry.example.com/team/api@sha256:3b1a9c...e2f

Phân biệt tag vs digest là nền tảng. Tag là một con trỏ mutable1.4 có thể được trỏ sang nội dung mới ngày mai. Digest (sha256:…) là địa chỉ nội dung — nó được suy ra từ chính các byte, nên pin theo digest đảm bảo bạn chạy đúng từng byte thứ đã test. Dùng tag dễ đọc để khám phá và digest cho manifest deploy thực tế. Bật tag immutability trên registry (ECR, ACR, Harbor, GAR đều hỗ trợ) ngăn bất kỳ ai push đè lên một tag đã tồn tại, khép lại khoảng cách giữa hai thứ.

Retention policy (chính sách lưu giữ)

Registry sẽ phình to vô hạn nếu không dọn dẹp; cả chi phí lưu trữ lẫn bề mặt tấn công đều tăng theo artifact tích trữ. Các chiều chính sách thường gặp:

// Lifecycle policy của AWS ECR: chỉ giữ 30 image gần nhất
{
  "rules": [{
    "rulePriority": 1,
    "description": "Keep last 30 images",
    "selection": {
      "tagStatus": "any",
      "countType": "imageCountMoreThan",
      "countNumber": 30
    },
    "action": { "type": "expire" }
  }]
}

Một policy thực tế hơn dùng nhiều rule theo tiền tố tag: hết hạn mạnh tay image pr-*snapshot-* sau vài ngày, giữ image release-* / gắn tag semver hàng tháng, và miễn trừ bất cứ thứ gì được một deployment đang chạy tham chiếu. Kiến trúc an toàn nhất làm cho retention biết được thứ gì đang thực sự deploy (ví dụ công cụ GitOps hoặc admission controller đánh dấu digest đang dùng) để việc dọn dẹp không bao giờ xóa một image đang chạy.

Provenance, ký số và SBOM

Đây là tầng bảo mật chuỗi cung ứng hiện đại, và ba mảnh trả lời ba câu hỏi khác nhau.

Provenance — “cái này từ đâu ra?” Metadata có thể xác minh về việc artifact được build như thế nào và ở đâu: source repo, commit SHA, danh tính builder, tham số build. Framework SLSA (Supply-chain Levels for Software Artifacts) định nghĩa các mức toàn vẹn build tăng dần; build attestation của GitHub Actions và các dịch vụ build cloud-native có thể sinh provenance đã ký tự động. Provenance cho người tiêu dùng xác minh “image này thực sự được build bởi CI đáng tin của chúng ta từ commit abc123”, chứ không phải bị kẻ tấn công cài vào.

Ký số — “đúng là của chúng ta và chưa bị sửa?” Ký artifact bằng mật mã để phía tiêu thụ xác minh người phát hành và rằng không có gì thay đổi sau khi ký. Sigstore/cosign khiến việc này khả thi với keyless signing: thay vì quản lý private key sống lâu, người ký dùng một certificate ngắn hạn gắn với danh tính OIDC của họ (ví dụ đúng workflow CI đó), được ghi vào một transparency log công khai (Rekor).

# Ký image (keyless, trong CI — danh tính đến từ OIDC token)
cosign sign registry.example.com/team/api@sha256:3b1a9c...e2f

# Verify trước khi deploy — khẳng định AI đã ký và ISSUER nào bảo chứng cho họ
cosign verify \
  --certificate-identity-regexp 'https://github.com/myorg/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  registry.example.com/team/api@sha256:3b1a9c...e2f

Lưu ý bạn verify theo digest, không phải tag — ký một tag mutable là vô nghĩa. Bước verify khẳng định danh tính đã ký (một workflow cụ thể) và issuer, nên chữ ký từ repo khác sẽ không qua.

SBOM — “bên trong có gì?” Software Bill of Materials là bản kê machine-readable (định dạng SPDX hoặc CycloneDX) về mọi component và dependency bên trong một artifact. Khi một CVE xuất hiện (Log4Shell, xz), SBOM biến câu “chúng ta có bị ảnh hưởng không?” từ một cuộc điều tra nhiều ngày thành một câu query database.

# Sinh SBOM từ image, rồi scan SBOM tìm lỗ hổng đã biết
syft registry.example.com/team/api:1.4.2 -o cyclonedx-json > sbom.json
grype sbom:sbom.json

# Đính SBOM và kết quả scan vào image dưới dạng attestation đã ký (trong registry)
cosign attest --predicate sbom.json --type cyclonedx \
  registry.example.com/team/api@sha256:3b1a9c...e2f

Khép vòng — cưỡng chế lúc deploy. Sinh provenance, chữ ký và SBOM mới chỉ là một nửa giá trị; phần thưởng là cưỡng chế chúng. Admission controller trên Kubernetes (Kyverno, Sigstore policy-controller, Connaisseur, OPA Gatekeeper) có thể từ chối bất kỳ image nào không được ký bởi danh tính CI của bạn hoặc thiếu attestation SBOM đạt yêu cầu. Điều này biến “chúng ta tin pipeline” thành đảm bảo được cluster cưỡng chế: một image không ký hoặc lạ mặt đơn giản là không thể khởi động ở production.

Phòng thủ dependency confusion và typosquatting

Hai cuộc tấn công chuỗi cung ứng phổ biến nhất nhắm vào bước resolution:

Best Practices

  1. Build một lần, promote khắp nơi — build lại cho từng môi trường làm mất giá trị của việc test; promote phải là copy/retag, không bao giờ compile lại. Thứ bạn đã test phải đúng từng byte thứ bạn ship.
  2. Làm cho release artifact bất biến — bật chặn overwrite/redeploy trên repo release và immutable tag trên registry; một version đã publish thì ý nghĩa của nó không bao giờ đổi. Giữ snapshot mutable ở một repo riêng.
  3. Không bao giờ deploy latest (hay bất kỳ tag di động nào) — deploy bằng tag version duy nhất, truy vết được và pin digest của container để thứ đang chạy đúng là thứ đã test và review.
  4. Proxy mọi registry công cộng — dẫn Maven Central, npm, PyPI, Docker Hub qua repository manager của bạn để cache, tăng độ sẵn sàng khi upstream sập, giảm rate limit (đặc biệt giới hạn pull ẩn danh của Docker Hub), có audit trail và một điểm chốt để chặn package độc hại.
  5. Phòng thủ dependency confusion — dùng scope cho tên package nội bộ, pin ưu tiên private-registry trên public, và cấu hình resolver sao cho tên nội bộ không bao giờ được lấy từ registry public.
  6. Dùng lockfile với integrity hashpackage-lock.json, poetry.lock, go.sum, Cargo.lock pin đúng version content hash, nên một dependency bị xâm nhập hay bị tráo sẽ fail kiểm tra integrity thay vì cài âm thầm.
  7. Scan artifact liên tục, không chỉ lúc build — CVE mới ra mỗi ngày nhắm vào component vốn sạch khi bạn build; scan lại image và package đã lưu theo lịch (Trivy, Grype, ECR scanning, Nexus IQ, Xray) và cảnh báo khi một version đang deploy trở nên có lỗ hổng.
  8. Tự động hóa retention với miễn trừ nhận biết production — lifecycle rule cho snapshot, manifest không tag và pre-release cũ giúp giảm chi phí lưu trữ lẫn bề mặt tấn công; luôn miễn trừ artifact được deployment đang chạy tham chiếu hoặc thuộc diện giữ compliance.
  9. Xác thực máy móc bằng credential ngắn hạn, phạm vi hẹp — dùng robot account và OIDC federation cho CI với quyền ghi giới hạn theo repo; ưu tiên token danh tính theo từng job thay vì credential tĩnh sống lâu; con người chủ yếu chỉ đọc.
  10. Ký artifact trong CI và verify lúc deploy — ký bằng cosign gắn với danh tính OIDC của CI, cộng với admission policy trong cluster từ chối image không ký, biến “tin pipeline” thành đảm bảo được cưỡng chế.
  11. Sinh và lưu SBOM cho mỗi release artifact — đính kèm trong registry dưới dạng attestation/referrer đã ký để phản ứng lỗ hổng trở thành một câu query, không phải cuộc khai quật, và để người tiêu dùng downstream audit được thứ họ đang chạy.
  12. Ghi và đính build provenance (SLSA) — lưu source repo, commit và danh tính builder để mọi binary đang chạy đều truy được về đúng source và build, và việc chỉnh sửa giữa build và deploy trở nên phát hiện được.
  13. Nhúng metadata truy vết vào artifact — đưa git SHA, build number, URL pipeline vào OCI label / property của artifact để một operator soi container đang chạy có thể nhảy thẳng tới source và build tạo ra nó.
  14. Tách repository theo mức tin cậy và vòng đời — repo riêng cho snapshot vs release, nội bộ vs public đã proxy, và theo team/môi trường, mỗi cái có permission và retention phù hợp. Một cái xô khổng lồ làm policy trở nên bất khả thi.
  15. Cưỡng chế least-privilege và quota trên registry — RBAC để team chỉ push vào namespace của mình, storage quota để một team không lấp đầy disk, và quyền read-only cho người tiêu dùng.
  16. Backup và lên phương án HA cho repository — artifact repo là dependency hạng nhất; nó sập thì bạn không build được (dependency), không deploy được (artifact), và cũng không rollback được (version cũ). Coi tính sẵn sàng của nó nghiêm túc như production database.

Tài liệu tham khảo

Part of the DevOps Roadmap knowledge base.

Overview

An artifact is any file produced by your build process that you deploy, distribute, or depend on: compiled binaries, language packages (JARs, wheels, npm tarballs), container images, Helm charts, OS packages (deb/rpm), and even machine-learning models. Artifact management is the discipline of storing, versioning, securing, and distributing these outputs through dedicated repositories rather than ad-hoc file shares or rebuilding from source every time.

In a healthy CI/CD pipeline, an artifact is built exactly once, given an immutable identity, and then promoted through environments (dev → staging → prod) unchanged. This “build once, deploy many” principle is what makes deployments reproducible and rollbacks trivial. Without an artifact repository, teams end up rebuilding per environment — which means the thing you tested is not literally the thing you shipped.

Artifact management has also become a security front line. Supply-chain attacks (dependency confusion, typosquatting, compromised registries) target exactly this layer, which is why modern practice adds provenance, signing (Sigstore/cosign), and SBOMs on top of plain storage.

Why a dedicated repository, and not just Git or a file share

A natural question is “why not commit artifacts to Git, or drop them on shared storage?” Three reasons make purpose-built repositories the standard:

  1. Binaries break version control. Git is built for diffable text; large binary blobs bloat history irreversibly and make clones painfully slow. Artifact repositories store binaries efficiently with deduplication.
  2. Protocol awareness. A real repository speaks the native protocols — Maven, npm, PyPI, NuGet, OCI/Docker Registry v2 — so your existing tools (mvn, npm, pip, docker pull) work unchanged by just pointing at a different URL.
  3. Metadata, search, and policy. Repositories track who published what, when, from which build, attach checksums and signatures, enforce retention, and answer “which artifacts contain log4j 2.14?” — none of which a file share can do.

The mental model: your artifact repository is the boundary between “code” and “running system.” Source flows in from Git, gets built into an immutable artifact, and every deployment pulls from the repository. If the repository is trustworthy and its contents are immutable and signed, you can reason about what is running in production. If it’s a free-for-all, you cannot.

Fundamentals

What counts as an artifact

TypeExamplesTypical format/registry protocol
Language packagesJAR/WAR, npm package, Python wheel, NuGet, Go module, Ruby gem, Cargo crateMaven, npm, PyPI, NuGet, Go proxy, crates.io
Container imagesApp images, base imagesOCI / Docker Registry v2
OS packages.deb, .rpm, apkAPT, YUM, Alpine repos
Deployment bundlesHelm charts, Terraform modules, WASM modulesOCI, Helm repo, Terraform registry
Generic binariesCLI tools, installers, firmware, ML modelsGeneric/raw repositories

A useful realization: OCI has quietly become the universal artifact format. Originally the container-image spec, the OCI registry now stores Helm charts, WASM modules, SBOMs, signatures, and arbitrary files as “OCI artifacts.” Increasingly, “push it to the registry as an OCI artifact” is the answer for anything that needs content-addressable, immutable, distributable storage — not just container images.

Roles of an artifact repository

  1. Local/hosted repositories — store artifacts you build (private packages, internal images). This is your source of truth for first-party artifacts.
  2. Proxy/remote repositories — cache upstream public registries (Maven Central, npmjs, Docker Hub, PyPI). Builds keep working when upstream is down or rate-limited, downloads are faster (cached locally) and auditable, and you gain a chokepoint to scan and block malicious packages before they reach developers.
  3. Virtual/group repositories — a single URL aggregating hosted + proxy repos, so build tools need only one endpoint. Resolution order matters: typically internal-hosted is searched before public-proxy so an attacker can’t shadow an internal package name (see dependency confusion below).

Major artifact repository managers

ToolModelStrengths
JFrog ArtifactoryCommercial (self-hosted or SaaS)Broadest format support (30+), virtual repos, mature enterprise features, Xray for security/license scanning
Sonatype Nexus RepositoryOSS + commercialPopular free option, solid Maven/npm/Docker support, pairs with Nexus IQ / Lifecycle for policy and scanning
GitHub PackagesSaaS, tied to GitHubZero-setup for GitHub teams; npm, Maven, NuGet, RubyGems, containers (ghcr.io); tight Actions integration
GitLab Package/Container RegistryBundled with GitLabIntegrated with GitLab CI; supports most package formats and container images
HarborCNCF open sourceContainer/OCI registry with RBAC, replication, built-in Trivy scanning, cosign signing, robot accounts, quotas
Docker HubSaaSDefault public image registry; official & verified images; rate limits for anonymous/free pulls
AWS ECR / Azure ACR / Google Artifact RegistryCloud-nativeIAM integration, geo-replication, scanning, immutable-tag enforcement; GAR also handles language packages (npm/Maven/PyPI)
Cloudsmith / GemfurySaaSManaged multi-format package hosting without running your own infra

Choosing between them, briefly: deep in a single cloud → the native registry (ECR/ACR/GAR) is the path of least resistance. On GitHub/GitLab → the bundled registry saves setup. Need one place for 20 formats with enterprise policy → Artifactory or Nexus. Want a self-hosted, security-focused container registry → Harbor.

Where artifacts fit in the pipeline

Build once, promote the same artifact
  1. 01Code push
  2. 02CI build
  3. 03test
  4. 04publish artifactv1.4.2 / sha256:…
  5. same artifact, different config
    05deploy to dev
  6. 06promote to staging
  7. 07promote to prod

Promotion is metadata movement (retag, copy between repos), never a rebuild. Configuration is injected at deploy time (env vars, config maps, secrets) so the same immutable artifact behaves correctly in each environment. If you find yourself passing environment-specific values into the build, you’ve broken build-once-deploy-many and can no longer trust that staging tested what production runs.

Key Concepts

Versioning strategies

# Build with an immutable, traceable tag
docker build -t registry.example.com/team/api:1.4.2-gitsha.9f8e7d6 .
docker push registry.example.com/team/api:1.4.2-gitsha.9f8e7d6

# Deploy pinned to the content digest (cannot be silently changed)
image: registry.example.com/team/api@sha256:3b1a9c...e2f

The tag vs digest distinction is fundamental. A tag is a mutable pointer1.4 can be repointed to new content tomorrow. A digest (sha256:…) is the content address — it is derived from the bytes themselves, so pinning to a digest guarantees you run byte-for-byte what you tested. Use human-readable tags for discovery and digests for the actual deploy manifest. Enabling tag immutability on the registry (ECR, ACR, Harbor, GAR all support it) prevents anyone from re-pushing over an existing tag, closing the gap between the two.

Retention policies

Registries grow without bound unless you prune; storage cost and attack surface both scale with hoarded artifacts. Typical policy dimensions:

// AWS ECR lifecycle policy: keep only the 30 most recent images
{
  "rules": [{
    "rulePriority": 1,
    "description": "Keep last 30 images",
    "selection": {
      "tagStatus": "any",
      "countType": "imageCountMoreThan",
      "countNumber": 30
    },
    "action": { "type": "expire" }
  }]
}

A more realistic policy uses multiple rules by tag prefix: aggressively expire pr-* and snapshot-* images after a few days, keep release-* / semver-tagged images for months, and exempt anything referenced by a running deployment. The safest architectures make retention aware of what’s actually deployed (e.g., GitOps tools or admission controllers that mark in-use digests) so cleanup can never delete a running image.

Provenance, signing, and SBOM

This is the modern supply-chain security layer, and the three pieces answer three different questions.

Provenance — “where did this come from?” Verifiable metadata about how and where an artifact was built: source repo, commit SHA, builder identity, build parameters. The SLSA framework (Supply-chain Levels for Software Artifacts) defines increasing levels of build integrity; GitHub Actions build attestations and cloud-native build services can generate signed provenance automatically. Provenance lets a consumer verify “this image really was built by our trusted CI from commit abc123,” not slipped in by an attacker.

Signing — “is this really from us, and untampered?” Cryptographically sign artifacts so consumers can verify the publisher and that nothing changed after signing. Sigstore/cosign made this practical with keyless signing: instead of managing long-lived private keys, the signer uses a short-lived certificate bound to its OIDC identity (e.g., the exact CI workflow), recorded in a public transparency log (Rekor).

# Sign an image (keyless, in CI — identity comes from the OIDC token)
cosign sign registry.example.com/team/api@sha256:3b1a9c...e2f

# Verify before deploying — assert WHO signed it and WHICH issuer vouched for them
cosign verify \
  --certificate-identity-regexp 'https://github.com/myorg/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  registry.example.com/team/api@sha256:3b1a9c...e2f

Note that you verify against a digest, not a tag — signing a mutable tag would be meaningless. The verify step asserts the identity that signed (a specific workflow) and the issuer, so a signature from some other repo won’t pass.

SBOM — “what’s inside?” A Software Bill of Materials is a machine-readable inventory (SPDX or CycloneDX format) of every component and dependency inside an artifact. When a CVE drops (Log4Shell, xz), an SBOM turns “are we affected?” from a multi-day investigation into a database query.

# Generate an SBOM from an image, then scan the SBOM for known vulnerabilities
syft registry.example.com/team/api:1.4.2 -o cyclonedx-json > sbom.json
grype sbom:sbom.json

# Attach the SBOM and vuln scan to the image as signed attestations (in-registry)
cosign attest --predicate sbom.json --type cyclonedx \
  registry.example.com/team/api@sha256:3b1a9c...e2f

Closing the loop — enforcement at deploy time. Generating provenance, signatures, and SBOMs is only half the value; the payoff is enforcing them. Kubernetes admission controllers (Kyverno, Sigstore policy-controller, Connaisseur, OPA Gatekeeper) can reject any image that isn’t signed by your CI’s identity or lacks a passing SBOM attestation. This turns “we trust our pipeline” into a cluster-enforced guarantee: an unsigned or unknown image simply cannot start in production.

Defending against dependency confusion and typosquatting

Two of the most common supply-chain attacks target the resolution step:

Best Practices

  1. Build once, promote everywhere — rebuilding per environment invalidates your testing; promotion should be a copy/retag, never a recompile. What you tested must be byte-for-byte what you ship.
  2. Make release artifacts immutable — enable “block redeploy/overwrite” on release repos and immutable tags on registries; a version, once published, never changes meaning. Keep mutable snapshots in a separate repo.
  3. Never deploy latest (or any moving tag) — deploy unique, traceable version tags and pin container digests so what runs is exactly what was tested and reviewed.
  4. Proxy all public registries — route Maven Central, npm, PyPI, Docker Hub through your repository manager for caching, availability during upstream outages, rate-limit relief (Docker Hub’s anonymous pull limits especially), audit trails, and a single chokepoint to block malicious packages.
  5. Defend against dependency confusion — scope internal package names, pin private-registry priority above public, and configure resolvers so an internal name can never be satisfied from a public registry.
  6. Use lockfiles with integrity hashespackage-lock.json, poetry.lock, go.sum, Cargo.lock pin exact versions and content hashes, so a compromised or swapped dependency fails the integrity check instead of installing silently.
  7. Scan artifacts continuously, not just at build time — new CVEs are published daily against components that were clean when you built; rescan stored images and packages on a schedule (Trivy, Grype, ECR scanning, Nexus IQ, Xray) and alert when a deployed version becomes vulnerable.
  8. Automate retention with a production-aware exemption — lifecycle rules for snapshots, untagged manifests, and old pre-releases keep storage and attack surface down; always exempt artifacts referenced by running deployments or compliance holds.
  9. Authenticate machines with scoped, short-lived credentials — use robot accounts and OIDC federation for CI with write access limited to specific repos; prefer per-job identity tokens over long-lived static credentials; keep humans read-mostly.
  10. Sign artifacts in CI and verify at deploy time — cosign signing bound to your CI’s OIDC identity, plus a cluster admission policy that rejects unsigned images, turns “trust the pipeline” into an enforced guarantee.
  11. Generate and store an SBOM per release artifact — attach it in the registry as a signed attestation/referrer so vulnerability response is a query, not an archaeology project, and downstream consumers can audit what they’re running.
  12. Capture and attach build provenance (SLSA) — record source repo, commit, and builder identity so any running binary is traceable to its exact source and build, and tampering between build and deploy is detectable.
  13. Embed traceability metadata in the artifact — include git SHA, build number, and pipeline URL as OCI labels / artifact properties so an operator inspecting a running container can jump straight to the source and build that produced it.
  14. Separate repositories by trust and lifecycle — distinct repos for snapshots vs releases, internal vs proxied-public, and per team/environment, each with appropriate permissions and retention. One giant bucket makes policy impossible.
  15. Enforce least-privilege and quotas on the registry — RBAC so teams push only to their own namespaces, storage quotas so one team can’t fill the disk, and read-only access for consumers.
  16. Back up and plan HA for the repository — the artifact repo is a tier-1 dependency; if it’s down, you can neither build (dependencies) nor deploy (artifacts) nor roll back (previous versions). Treat its availability with the same seriousness as your production database.

References