Skip to content

Security ​

Canonical source

This is an overview. The authoritative, maintained design lives in SECURITY.md at the repo root — it is the source of truth.

roci's security posture is reverse-engineered from zot's published security posture and adapted to Rust.

Build-time hardening ​

  • Every crate carries #![forbid(unsafe_code)] unless it is an audited zero-copy module explicitly exempted (security invariant 7).
  • Supply-chain gating via cargo deny; pinned toolchain; static musl builds.

Runtime hardening ​

  • Rootless by default; the container image runs as a nonroot UID on a scratch base with a read-only root filesystem and only the storage volume writable.

Kubernetes controls ​

The Helm chart runs every workload PSS-restricted with default-deny NetworkPolicies, no ServiceAccount token or RBAC, a secure-by-default auth guard, digest-pinned dependency images, and roci's secrets as 0440 file mounts. Unauthenticated health endpoints (/readyz, /livez) expose only a readiness flag and a short reason string — no internal state or version info. Private-CA trust for S3 endpoints outside the chart is supported via the ca_file config key; RustFS client-cert mTLS is blocked (no client-cert API in object_store; no server-TLS-only mode in the RustFS subchart). See Kubernetes controls (Helm chart) in the canonical doc.

Authentication & authorization ​

[implemented — Phase 6] roci supports the full authn/authz matrix: HTTP Basic (local htpasswd with bcrypt; LDAP bind via the opt-in ldap feature, not in full), external Bearer token verification (ES256/RS256 over ring), mTLS client-certificate authentication with optional CA/leaf-fingerprint pinning, and Identity-Based Access Control (IBAC) with glob-pattern policies, specificity-based rule matching, admin/group support, and live-reloadable authorization. Auth is opt-in; without configuration the registry behaves identically to a no-auth build. Bearer token principals are authorized by their token's access claims only (IBAC not consulted). The /metrics endpoint stays unauthenticated. See SECURITY.md for the full authn order, decision→response matrix, challenge header rules, and credential-cache design.

Content trust & integrity ​

SHA-512 default digests (SHA-256 accepted) with constant-time verification; cosign and notation signatures; verified streaming for per-Range-chunk integrity. 307 redirect SSRF containment via a derived host allowlist and internal-host rejection. 0-RTT hardening: 425 Too Early for proxy-forwarded early data on non-idempotent methods (RFC 8470 §5.1).

Request- & storage-boundary controls ​

Path-traversal-safe validation, a wire digest allowlist, bounded inputs (config-driven size / n caps, JSON depth), header-read + idle timeouts, global per-HTTP-method rate limits and per-client rate limits (429 TOOMANYREQUESTS, LRU-bounded client map keyed by principal or peer IP), TLS 0-RTT hardening, repository isolation (no cross-repo presence or content oracle), cross-repo mount double-authorization, and SSRF containment (no client-URL fetch; host-allowlisted, repo-gated redirects). On the storage side: storage quotas and a concurrent upload-session cap against exhaustion, GC that can never delete a blob a push is about to reference, a manifest and its derived links committed as one metadata record, scrub quarantine of blobs that no longer match their digest, and optional HMAC authentication of the metadata WAL against a tampered-storage threat model. See the canonical SECURITY.md for the full boundary analysis, CVE mappings, and invariant list.

Security invariants & CVE regression suite ​

The canonical doc enumerates security invariants that must never regress, plus a tracked set of prior-art CVE classes exercised as a regression suite in CI. Changing an invariant requires updating SECURITY.md and flagging the change.

Reporting

Report security issues per the process in SECURITY.md — do not open a public issue for a vulnerability.

Released under the Apache License 2.0.