From a90bcc51607b43786688f665d7bf4ac43f22d352 Mon Sep 17 00:00:00 2001 From: rchincha Date: Wed, 13 Mar 2024 21:38:51 +0000 Subject: [PATCH] Deployed be2ac39 to v2.0.2 with MkDocs 1.4.2 and mike 1.1.2 --- latest/404.html | 6 +- .../admin-configuration/index.html | 6 +- .../admin-getting-started/index.html | 6 +- latest/articles/authn-authz/index.html | 6 +- .../articles/benchmarking-with-zb/index.html | 6 +- .../building-ci-cd-pipeline/index.html | 6 +- latest/articles/clustering/index.html | 6 +- latest/articles/graphql/index.html | 6 +- latest/articles/immutable-tags/index.html | 17 + latest/articles/kind-deploy/index.html | 6 +- latest/articles/mirroring/index.html | 6 +- latest/articles/monitoring/index.html | 6 +- latest/articles/pprofiling/index.html | 6 +- latest/articles/retention/index.html | 6 +- latest/articles/security-posture/index.html | 6 +- latest/articles/storage/index.html | 6 +- .../articles/verifying-signatures/index.html | 6 +- latest/articles/workflow/index.html | 6 +- .../developer-guide/api-reference/index.html | 6 +- .../developer-guide/api-user-guide/index.html | 6 +- .../developer-guide/contributing/index.html | 6 +- .../developer-guide/extensions-dev/index.html | 6 +- latest/developer-guide/onboarding/index.html | 6 +- latest/general/architecture/index.html | 6 +- latest/general/concepts/index.html | 6 +- latest/general/extensions/index.html | 6 +- latest/general/features/index.html | 6 +- latest/general/glossary/index.html | 6 +- latest/general/project/index.html | 6 +- latest/general/releases/index.html | 6 +- latest/general/whats-new/index.html | 6 +- latest/index.html | 6 +- .../install-guide-k8s/index.html | 6 +- .../install-guide-linux/index.html | 6 +- .../user-guide-datapath/index.html | 6 +- latest/user-guides/user-guide-gui/index.html | 6 +- latest/user-guides/zli/index.html | 6 +- v2.0.2/404.html | 1 + .../admin-configuration/index.html | 121 + .../admin-getting-started/index.html | 19 + v2.0.2/articles/authn-authz/index.html | 188 + .../articles/benchmarking-with-zb/index.html | 54 + .../building-ci-cd-pipeline/index.html | 27 + v2.0.2/articles/clustering/index.html | 76 + v2.0.2/articles/graphql/index.html | 598 + v2.0.2/articles/immutable-tags/index.html | 23 + v2.0.2/articles/kind-deploy/index.html | 124 + v2.0.2/articles/mirroring/index.html | 248 + v2.0.2/articles/monitoring/index.html | 27 + v2.0.2/articles/pprofiling/index.html | 32 + v2.0.2/articles/retention/index.html | 99 + v2.0.2/articles/security-posture/index.html | 1 + v2.0.2/articles/storage/index.html | 165 + .../articles/verifying-signatures/index.html | 86 + v2.0.2/articles/workflow/index.html | 207 + v2.0.2/assets/images/504566.jpg | Bin 0 -> 256139 bytes v2.0.2/assets/images/504567.jpg | Bin 0 -> 209672 bytes v2.0.2/assets/images/504568.jpg | Bin 0 -> 132897 bytes v2.0.2/assets/images/504569.jpg | Bin 0 -> 56377 bytes v2.0.2/assets/images/alpine_bookmarked.png | Bin 0 -> 39176 bytes .../assets/images/alpine_not_bookmarked.png | Bin 0 -> 38407 bytes v2.0.2/assets/images/bookmarked_off.png | Bin 0 -> 532 bytes v2.0.2/assets/images/bookmarked_on.png | Bin 0 -> 401 bytes v2.0.2/assets/images/cosign.svg | 1 + v2.0.2/assets/images/critical.jpg | Bin 0 -> 3302 bytes v2.0.2/assets/images/favicon.png | Bin 0 -> 1870 bytes v2.0.2/assets/images/high.jpg | Bin 0 -> 3094 bytes v2.0.2/assets/images/icon-failed-to-scan.jpg | Bin 0 -> 2689 bytes .../assets/images/icon-no-vulnerability.jpg | Bin 0 -> 2493 bytes .../images/icon-unverified-signature.jpg | Bin 0 -> 2476 bytes .../assets/images/icon-verified-signature.jpg | Bin 0 -> 2373 bytes v2.0.2/assets/images/illustrations/arch.jpg | Bin 0 -> 209672 bytes v2.0.2/assets/images/illustrations/home.png | Bin 0 -> 115972 bytes v2.0.2/assets/images/layers-details.jpg | Bin 0 -> 74219 bytes v2.0.2/assets/images/logo.png | Bin 0 -> 12007 bytes v2.0.2/assets/images/logo.svg | 25 + v2.0.2/assets/images/low.jpg | Bin 0 -> 3161 bytes v2.0.2/assets/images/medium.jpg | Bin 0 -> 3336 bytes v2.0.2/assets/images/pprof-view.jpg | Bin 0 -> 46033 bytes v2.0.2/assets/images/profile001.png | Bin 0 -> 22450 bytes v2.0.2/assets/images/profiling-flame.svg | 15285 ++++++++++++++++ v2.0.2/assets/images/pull-image.jpg | Bin 0 -> 40955 bytes v2.0.2/assets/images/screen-initial.jpg | Bin 0 -> 354806 bytes v2.0.2/assets/images/screen-layers.jpg | Bin 0 -> 254665 bytes v2.0.2/assets/images/screen-tags.jpg | Bin 0 -> 292294 bytes v2.0.2/assets/images/screen-view-all.jpg | Bin 0 -> 380105 bytes v2.0.2/assets/images/tile.jpg | Bin 0 -> 66817 bytes v2.0.2/assets/images/zot-logo-192x192.png | Bin 0 -> 12007 bytes v2.0.2/assets/images/zot-logo-70x70.png | Bin 0 -> 6160 bytes .../assets/javascripts/bundle.5cf534bf.min.js | 29 + .../javascripts/bundle.5cf534bf.min.js.map | 8 + .../javascripts/lunr/min/lunr.ar.min.js | 1 + .../javascripts/lunr/min/lunr.da.min.js | 18 + .../javascripts/lunr/min/lunr.de.min.js | 18 + .../javascripts/lunr/min/lunr.du.min.js | 18 + .../javascripts/lunr/min/lunr.es.min.js | 18 + .../javascripts/lunr/min/lunr.fi.min.js | 18 + .../javascripts/lunr/min/lunr.fr.min.js | 18 + .../javascripts/lunr/min/lunr.hi.min.js | 1 + .../javascripts/lunr/min/lunr.hu.min.js | 18 + .../javascripts/lunr/min/lunr.it.min.js | 18 + .../javascripts/lunr/min/lunr.ja.min.js | 1 + .../javascripts/lunr/min/lunr.jp.min.js | 1 + .../javascripts/lunr/min/lunr.ko.min.js | 1 + .../javascripts/lunr/min/lunr.multi.min.js | 1 + .../javascripts/lunr/min/lunr.nl.min.js | 18 + .../javascripts/lunr/min/lunr.no.min.js | 18 + .../javascripts/lunr/min/lunr.pt.min.js | 18 + .../javascripts/lunr/min/lunr.ro.min.js | 18 + .../javascripts/lunr/min/lunr.ru.min.js | 18 + .../lunr/min/lunr.stemmer.support.min.js | 1 + .../javascripts/lunr/min/lunr.sv.min.js | 18 + .../javascripts/lunr/min/lunr.ta.min.js | 1 + .../javascripts/lunr/min/lunr.th.min.js | 1 + .../javascripts/lunr/min/lunr.tr.min.js | 18 + .../javascripts/lunr/min/lunr.vi.min.js | 1 + .../javascripts/lunr/min/lunr.zh.min.js | 1 + v2.0.2/assets/javascripts/lunr/tinyseg.js | 206 + v2.0.2/assets/javascripts/lunr/wordcut.js | 6708 +++++++ .../workers/search.12658920.min.js | 42 + .../workers/search.12658920.min.js.map | 8 + .../assets/stylesheets/main.f56500e0.min.css | 1 + .../stylesheets/main.f56500e0.min.css.map | 1 + .../stylesheets/palette.2505c338.min.css | 1 + .../stylesheets/palette.2505c338.min.css.map | 1 + .../developer-guide/api-reference/index.html | 312 + .../developer-guide/api-user-guide/index.html | 77 + .../developer-guide/contributing/index.html | 1 + .../developer-guide/extensions-dev/index.html | 18 + v2.0.2/developer-guide/onboarding/index.html | 29 + v2.0.2/general/architecture/index.html | 1 + v2.0.2/general/concepts/index.html | 1 + v2.0.2/general/extensions/index.html | 1 + v2.0.2/general/features/index.html | 1 + v2.0.2/general/glossary/index.html | 1 + v2.0.2/general/project/index.html | 1 + v2.0.2/general/releases/index.html | 3 + v2.0.2/general/whats-new/index.html | 2 + v2.0.2/index.html | 1 + .../install-guide-k8s/index.html | 79 + .../install-guide-linux/index.html | 115 + .../assets/javascripts/bundle.e5217812.min.js | 16 + .../javascripts/bundle.e5217812.min.js.map | 1 + .../assets/javascripts/icon_search_index.json | 1 + .../assets/stylesheets/main.01a7853e.min.css | 3 + .../stylesheets/main.01a7853e.min.css.map | 1 + v2.0.2/pdf/document.pdf | Bin 0 -> 5645790 bytes v2.0.2/search/search_index.json | 1 + v2.0.2/sitemap.xml | 183 + v2.0.2/sitemap.xml.gz | Bin 0 -> 563 bytes v2.0.2/stylesheets/custom.css | 56 + .../user-guide-datapath/index.html | 55 + v2.0.2/user-guides/user-guide-gui/index.html | 1 + v2.0.2/user-guides/zli/index.html | 306 + versions.json | 2 +- zot/404.html | 6 +- .../admin-configuration/index.html | 6 +- .../admin-getting-started/index.html | 6 +- zot/articles/authn-authz/index.html | 6 +- zot/articles/benchmarking-with-zb/index.html | 6 +- .../building-ci-cd-pipeline/index.html | 6 +- zot/articles/clustering/index.html | 6 +- zot/articles/graphql/index.html | 6 +- zot/articles/immutable-tags/index.html | 17 + zot/articles/kind-deploy/index.html | 6 +- zot/articles/mirroring/index.html | 6 +- zot/articles/monitoring/index.html | 6 +- zot/articles/pprofiling/index.html | 6 +- zot/articles/retention/index.html | 6 +- zot/articles/security-posture/index.html | 6 +- zot/articles/storage/index.html | 6 +- zot/articles/verifying-signatures/index.html | 6 +- zot/articles/workflow/index.html | 6 +- zot/developer-guide/api-reference/index.html | 6 +- zot/developer-guide/api-user-guide/index.html | 6 +- zot/developer-guide/contributing/index.html | 6 +- zot/developer-guide/extensions-dev/index.html | 6 +- zot/developer-guide/onboarding/index.html | 6 +- zot/general/architecture/index.html | 6 +- zot/general/concepts/index.html | 6 +- zot/general/extensions/index.html | 6 +- zot/general/features/index.html | 6 +- zot/general/glossary/index.html | 6 +- zot/general/project/index.html | 6 +- zot/general/releases/index.html | 6 +- zot/general/whats-new/index.html | 6 +- zot/index.html | 6 +- .../install-guide-k8s/index.html | 6 +- .../install-guide-linux/index.html | 6 +- .../user-guide-datapath/index.html | 6 +- zot/user-guides/user-guide-gui/index.html | 6 +- zot/user-guides/zli/index.html | 6 +- 192 files changed, 26211 insertions(+), 217 deletions(-) create mode 100644 latest/articles/immutable-tags/index.html create mode 100644 v2.0.2/404.html create mode 100644 v2.0.2/admin-guide/admin-configuration/index.html create mode 100644 v2.0.2/admin-guide/admin-getting-started/index.html create mode 100644 v2.0.2/articles/authn-authz/index.html create mode 100644 v2.0.2/articles/benchmarking-with-zb/index.html create mode 100644 v2.0.2/articles/building-ci-cd-pipeline/index.html create mode 100644 v2.0.2/articles/clustering/index.html create mode 100644 v2.0.2/articles/graphql/index.html create mode 100644 v2.0.2/articles/immutable-tags/index.html create mode 100644 v2.0.2/articles/kind-deploy/index.html create mode 100644 v2.0.2/articles/mirroring/index.html create mode 100644 v2.0.2/articles/monitoring/index.html create mode 100644 v2.0.2/articles/pprofiling/index.html create mode 100644 v2.0.2/articles/retention/index.html create mode 100644 v2.0.2/articles/security-posture/index.html create mode 100644 v2.0.2/articles/storage/index.html create mode 100644 v2.0.2/articles/verifying-signatures/index.html create mode 100644 v2.0.2/articles/workflow/index.html create mode 100644 v2.0.2/assets/images/504566.jpg create mode 100644 v2.0.2/assets/images/504567.jpg create mode 100644 v2.0.2/assets/images/504568.jpg create mode 100644 v2.0.2/assets/images/504569.jpg create mode 100644 v2.0.2/assets/images/alpine_bookmarked.png create mode 100644 v2.0.2/assets/images/alpine_not_bookmarked.png create mode 100644 v2.0.2/assets/images/bookmarked_off.png create mode 100644 v2.0.2/assets/images/bookmarked_on.png create mode 100644 v2.0.2/assets/images/cosign.svg create mode 100644 v2.0.2/assets/images/critical.jpg create mode 100644 v2.0.2/assets/images/favicon.png create mode 100644 v2.0.2/assets/images/high.jpg create mode 100644 v2.0.2/assets/images/icon-failed-to-scan.jpg create mode 100644 v2.0.2/assets/images/icon-no-vulnerability.jpg create mode 100644 v2.0.2/assets/images/icon-unverified-signature.jpg create mode 100644 v2.0.2/assets/images/icon-verified-signature.jpg create mode 100644 v2.0.2/assets/images/illustrations/arch.jpg create mode 100644 v2.0.2/assets/images/illustrations/home.png create mode 100644 v2.0.2/assets/images/layers-details.jpg create mode 100644 v2.0.2/assets/images/logo.png create mode 100644 v2.0.2/assets/images/logo.svg create mode 100644 v2.0.2/assets/images/low.jpg create mode 100644 v2.0.2/assets/images/medium.jpg create mode 100644 v2.0.2/assets/images/pprof-view.jpg create mode 100644 v2.0.2/assets/images/profile001.png create mode 100644 v2.0.2/assets/images/profiling-flame.svg create mode 100644 v2.0.2/assets/images/pull-image.jpg create mode 100644 v2.0.2/assets/images/screen-initial.jpg create mode 100644 v2.0.2/assets/images/screen-layers.jpg create mode 100644 v2.0.2/assets/images/screen-tags.jpg create mode 100644 v2.0.2/assets/images/screen-view-all.jpg create mode 100644 v2.0.2/assets/images/tile.jpg create mode 100644 v2.0.2/assets/images/zot-logo-192x192.png create mode 100644 v2.0.2/assets/images/zot-logo-70x70.png create mode 100644 v2.0.2/assets/javascripts/bundle.5cf534bf.min.js create mode 100644 v2.0.2/assets/javascripts/bundle.5cf534bf.min.js.map create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 v2.0.2/assets/javascripts/lunr/tinyseg.js create mode 100644 v2.0.2/assets/javascripts/lunr/wordcut.js create mode 100644 v2.0.2/assets/javascripts/workers/search.12658920.min.js create mode 100644 v2.0.2/assets/javascripts/workers/search.12658920.min.js.map create mode 100644 v2.0.2/assets/stylesheets/main.f56500e0.min.css create mode 100644 v2.0.2/assets/stylesheets/main.f56500e0.min.css.map create mode 100644 v2.0.2/assets/stylesheets/palette.2505c338.min.css create mode 100644 v2.0.2/assets/stylesheets/palette.2505c338.min.css.map create mode 100644 v2.0.2/developer-guide/api-reference/index.html create mode 100644 v2.0.2/developer-guide/api-user-guide/index.html create mode 100644 v2.0.2/developer-guide/contributing/index.html create mode 100644 v2.0.2/developer-guide/extensions-dev/index.html create mode 100644 v2.0.2/developer-guide/onboarding/index.html create mode 100644 v2.0.2/general/architecture/index.html create mode 100644 v2.0.2/general/concepts/index.html create mode 100644 v2.0.2/general/extensions/index.html create mode 100644 v2.0.2/general/features/index.html create mode 100644 v2.0.2/general/glossary/index.html create mode 100644 v2.0.2/general/project/index.html create mode 100644 v2.0.2/general/releases/index.html create mode 100644 v2.0.2/general/whats-new/index.html create mode 100644 v2.0.2/index.html create mode 100644 v2.0.2/install-guides/install-guide-k8s/index.html create mode 100644 v2.0.2/install-guides/install-guide-linux/index.html create mode 100644 v2.0.2/overrides/assets/javascripts/bundle.e5217812.min.js create mode 100644 v2.0.2/overrides/assets/javascripts/bundle.e5217812.min.js.map create mode 100644 v2.0.2/overrides/assets/javascripts/icon_search_index.json create mode 100644 v2.0.2/overrides/assets/stylesheets/main.01a7853e.min.css create mode 100644 v2.0.2/overrides/assets/stylesheets/main.01a7853e.min.css.map create mode 100644 v2.0.2/pdf/document.pdf create mode 100644 v2.0.2/search/search_index.json create mode 100644 v2.0.2/sitemap.xml create mode 100644 v2.0.2/sitemap.xml.gz create mode 100644 v2.0.2/stylesheets/custom.css create mode 100644 v2.0.2/user-guides/user-guide-datapath/index.html create mode 100644 v2.0.2/user-guides/user-guide-gui/index.html create mode 100644 v2.0.2/user-guides/zli/index.html create mode 100644 zot/articles/immutable-tags/index.html diff --git a/latest/404.html b/latest/404.html index 0aea49c..3bc7e6c 100644 --- a/latest/404.html +++ b/latest/404.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../v2.0.1/404.html... + Redirecting to ../v2.0.2/404.html... \ No newline at end of file diff --git a/latest/admin-guide/admin-configuration/index.html b/latest/admin-guide/admin-configuration/index.html index 07d4263..9832a93 100644 --- a/latest/admin-guide/admin-configuration/index.html +++ b/latest/admin-guide/admin-configuration/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/admin-guide/admin-configuration/... + Redirecting to ../../../v2.0.2/admin-guide/admin-configuration/... \ No newline at end of file diff --git a/latest/admin-guide/admin-getting-started/index.html b/latest/admin-guide/admin-getting-started/index.html index dbf76ab..bcc323a 100644 --- a/latest/admin-guide/admin-getting-started/index.html +++ b/latest/admin-guide/admin-getting-started/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/admin-guide/admin-getting-started/... + Redirecting to ../../../v2.0.2/admin-guide/admin-getting-started/... \ No newline at end of file diff --git a/latest/articles/authn-authz/index.html b/latest/articles/authn-authz/index.html index e750771..004a67c 100644 --- a/latest/articles/authn-authz/index.html +++ b/latest/articles/authn-authz/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/authn-authz/... + Redirecting to ../../../v2.0.2/articles/authn-authz/... \ No newline at end of file diff --git a/latest/articles/benchmarking-with-zb/index.html b/latest/articles/benchmarking-with-zb/index.html index b3416b7..4053ba9 100644 --- a/latest/articles/benchmarking-with-zb/index.html +++ b/latest/articles/benchmarking-with-zb/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/benchmarking-with-zb/... + Redirecting to ../../../v2.0.2/articles/benchmarking-with-zb/... \ No newline at end of file diff --git a/latest/articles/building-ci-cd-pipeline/index.html b/latest/articles/building-ci-cd-pipeline/index.html index 93c2ddc..148ca9b 100644 --- a/latest/articles/building-ci-cd-pipeline/index.html +++ b/latest/articles/building-ci-cd-pipeline/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/building-ci-cd-pipeline/... + Redirecting to ../../../v2.0.2/articles/building-ci-cd-pipeline/... \ No newline at end of file diff --git a/latest/articles/clustering/index.html b/latest/articles/clustering/index.html index 9cfcc66..d0ca945 100644 --- a/latest/articles/clustering/index.html +++ b/latest/articles/clustering/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/clustering/... + Redirecting to ../../../v2.0.2/articles/clustering/... \ No newline at end of file diff --git a/latest/articles/graphql/index.html b/latest/articles/graphql/index.html index a403ca8..63e9092 100644 --- a/latest/articles/graphql/index.html +++ b/latest/articles/graphql/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/graphql/... + Redirecting to ../../../v2.0.2/articles/graphql/... \ No newline at end of file diff --git a/latest/articles/immutable-tags/index.html b/latest/articles/immutable-tags/index.html new file mode 100644 index 0000000..1f81012 --- /dev/null +++ b/latest/articles/immutable-tags/index.html @@ -0,0 +1,17 @@ + + + + + Redirecting + + + + + Redirecting to ../../../v2.0.2/articles/immutable-tags/... + + \ No newline at end of file diff --git a/latest/articles/kind-deploy/index.html b/latest/articles/kind-deploy/index.html index 3cb6e65..f67927f 100644 --- a/latest/articles/kind-deploy/index.html +++ b/latest/articles/kind-deploy/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/kind-deploy/... + Redirecting to ../../../v2.0.2/articles/kind-deploy/... \ No newline at end of file diff --git a/latest/articles/mirroring/index.html b/latest/articles/mirroring/index.html index 27f210f..15af30b 100644 --- a/latest/articles/mirroring/index.html +++ b/latest/articles/mirroring/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/mirroring/... + Redirecting to ../../../v2.0.2/articles/mirroring/... \ No newline at end of file diff --git a/latest/articles/monitoring/index.html b/latest/articles/monitoring/index.html index f06afc7..116248f 100644 --- a/latest/articles/monitoring/index.html +++ b/latest/articles/monitoring/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/monitoring/... + Redirecting to ../../../v2.0.2/articles/monitoring/... \ No newline at end of file diff --git a/latest/articles/pprofiling/index.html b/latest/articles/pprofiling/index.html index 1eb49f2..066784b 100644 --- a/latest/articles/pprofiling/index.html +++ b/latest/articles/pprofiling/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/pprofiling/... + Redirecting to ../../../v2.0.2/articles/pprofiling/... \ No newline at end of file diff --git a/latest/articles/retention/index.html b/latest/articles/retention/index.html index e70ba71..1abae58 100644 --- a/latest/articles/retention/index.html +++ b/latest/articles/retention/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/retention/... + Redirecting to ../../../v2.0.2/articles/retention/... \ No newline at end of file diff --git a/latest/articles/security-posture/index.html b/latest/articles/security-posture/index.html index 7a8fdef..fa02dfb 100644 --- a/latest/articles/security-posture/index.html +++ b/latest/articles/security-posture/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/security-posture/... + Redirecting to ../../../v2.0.2/articles/security-posture/... \ No newline at end of file diff --git a/latest/articles/storage/index.html b/latest/articles/storage/index.html index 5310b8f..7c629ed 100644 --- a/latest/articles/storage/index.html +++ b/latest/articles/storage/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/storage/... + Redirecting to ../../../v2.0.2/articles/storage/... \ No newline at end of file diff --git a/latest/articles/verifying-signatures/index.html b/latest/articles/verifying-signatures/index.html index ba89d02..09e06de 100644 --- a/latest/articles/verifying-signatures/index.html +++ b/latest/articles/verifying-signatures/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/verifying-signatures/... + Redirecting to ../../../v2.0.2/articles/verifying-signatures/... \ No newline at end of file diff --git a/latest/articles/workflow/index.html b/latest/articles/workflow/index.html index 53c5599..6ad0f1c 100644 --- a/latest/articles/workflow/index.html +++ b/latest/articles/workflow/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/articles/workflow/... + Redirecting to ../../../v2.0.2/articles/workflow/... \ No newline at end of file diff --git a/latest/developer-guide/api-reference/index.html b/latest/developer-guide/api-reference/index.html index 0fa1549..db98591 100644 --- a/latest/developer-guide/api-reference/index.html +++ b/latest/developer-guide/api-reference/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/developer-guide/api-reference/... + Redirecting to ../../../v2.0.2/developer-guide/api-reference/... \ No newline at end of file diff --git a/latest/developer-guide/api-user-guide/index.html b/latest/developer-guide/api-user-guide/index.html index 33fa4c6..2a77f4f 100644 --- a/latest/developer-guide/api-user-guide/index.html +++ b/latest/developer-guide/api-user-guide/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/developer-guide/api-user-guide/... + Redirecting to ../../../v2.0.2/developer-guide/api-user-guide/... \ No newline at end of file diff --git a/latest/developer-guide/contributing/index.html b/latest/developer-guide/contributing/index.html index 15c00b0..c3fa106 100644 --- a/latest/developer-guide/contributing/index.html +++ b/latest/developer-guide/contributing/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/developer-guide/contributing/... + Redirecting to ../../../v2.0.2/developer-guide/contributing/... \ No newline at end of file diff --git a/latest/developer-guide/extensions-dev/index.html b/latest/developer-guide/extensions-dev/index.html index 180f863..fe7c709 100644 --- a/latest/developer-guide/extensions-dev/index.html +++ b/latest/developer-guide/extensions-dev/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/developer-guide/extensions-dev/... + Redirecting to ../../../v2.0.2/developer-guide/extensions-dev/... \ No newline at end of file diff --git a/latest/developer-guide/onboarding/index.html b/latest/developer-guide/onboarding/index.html index 6f0d5fc..fd33037 100644 --- a/latest/developer-guide/onboarding/index.html +++ b/latest/developer-guide/onboarding/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/developer-guide/onboarding/... + Redirecting to ../../../v2.0.2/developer-guide/onboarding/... \ No newline at end of file diff --git a/latest/general/architecture/index.html b/latest/general/architecture/index.html index 4819a3d..1435238 100644 --- a/latest/general/architecture/index.html +++ b/latest/general/architecture/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/architecture/... + Redirecting to ../../../v2.0.2/general/architecture/... \ No newline at end of file diff --git a/latest/general/concepts/index.html b/latest/general/concepts/index.html index 4430e56..c6e00c2 100644 --- a/latest/general/concepts/index.html +++ b/latest/general/concepts/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/concepts/... + Redirecting to ../../../v2.0.2/general/concepts/... \ No newline at end of file diff --git a/latest/general/extensions/index.html b/latest/general/extensions/index.html index a994523..51a37cc 100644 --- a/latest/general/extensions/index.html +++ b/latest/general/extensions/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/extensions/... + Redirecting to ../../../v2.0.2/general/extensions/... \ No newline at end of file diff --git a/latest/general/features/index.html b/latest/general/features/index.html index 490b3f8..c26a00d 100644 --- a/latest/general/features/index.html +++ b/latest/general/features/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/features/... + Redirecting to ../../../v2.0.2/general/features/... \ No newline at end of file diff --git a/latest/general/glossary/index.html b/latest/general/glossary/index.html index 4b862be..919affd 100644 --- a/latest/general/glossary/index.html +++ b/latest/general/glossary/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/glossary/... + Redirecting to ../../../v2.0.2/general/glossary/... \ No newline at end of file diff --git a/latest/general/project/index.html b/latest/general/project/index.html index 21c9878..3dd2cdc 100644 --- a/latest/general/project/index.html +++ b/latest/general/project/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/project/... + Redirecting to ../../../v2.0.2/general/project/... \ No newline at end of file diff --git a/latest/general/releases/index.html b/latest/general/releases/index.html index 1b13a50..916673f 100644 --- a/latest/general/releases/index.html +++ b/latest/general/releases/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/releases/... + Redirecting to ../../../v2.0.2/general/releases/... \ No newline at end of file diff --git a/latest/general/whats-new/index.html b/latest/general/whats-new/index.html index 3a6f2a5..3b9665e 100644 --- a/latest/general/whats-new/index.html +++ b/latest/general/whats-new/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/general/whats-new/... + Redirecting to ../../../v2.0.2/general/whats-new/... \ No newline at end of file diff --git a/latest/index.html b/latest/index.html index c3657da..1959f8f 100644 --- a/latest/index.html +++ b/latest/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../v2.0.1/... + Redirecting to ../v2.0.2/... \ No newline at end of file diff --git a/latest/install-guides/install-guide-k8s/index.html b/latest/install-guides/install-guide-k8s/index.html index 7b3560f..fee5175 100644 --- a/latest/install-guides/install-guide-k8s/index.html +++ b/latest/install-guides/install-guide-k8s/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/install-guides/install-guide-k8s/... + Redirecting to ../../../v2.0.2/install-guides/install-guide-k8s/... \ No newline at end of file diff --git a/latest/install-guides/install-guide-linux/index.html b/latest/install-guides/install-guide-linux/index.html index eae4aca..9e121ec 100644 --- a/latest/install-guides/install-guide-linux/index.html +++ b/latest/install-guides/install-guide-linux/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/install-guides/install-guide-linux/... + Redirecting to ../../../v2.0.2/install-guides/install-guide-linux/... \ No newline at end of file diff --git a/latest/user-guides/user-guide-datapath/index.html b/latest/user-guides/user-guide-datapath/index.html index cbb58e1..58e66de 100644 --- a/latest/user-guides/user-guide-datapath/index.html +++ b/latest/user-guides/user-guide-datapath/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/user-guides/user-guide-datapath/... + Redirecting to ../../../v2.0.2/user-guides/user-guide-datapath/... \ No newline at end of file diff --git a/latest/user-guides/user-guide-gui/index.html b/latest/user-guides/user-guide-gui/index.html index 90a80d0..6276cef 100644 --- a/latest/user-guides/user-guide-gui/index.html +++ b/latest/user-guides/user-guide-gui/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/user-guides/user-guide-gui/... + Redirecting to ../../../v2.0.2/user-guides/user-guide-gui/... \ No newline at end of file diff --git a/latest/user-guides/zli/index.html b/latest/user-guides/zli/index.html index afc343f..c0d758b 100644 --- a/latest/user-guides/zli/index.html +++ b/latest/user-guides/zli/index.html @@ -5,13 +5,13 @@ Redirecting - Redirecting to ../../../v2.0.1/user-guides/zli/... + Redirecting to ../../../v2.0.2/user-guides/zli/... \ No newline at end of file diff --git a/v2.0.2/404.html b/v2.0.2/404.html new file mode 100644 index 0000000..a4d0111 --- /dev/null +++ b/v2.0.2/404.html @@ -0,0 +1 @@ + zotregistry.dev
\ No newline at end of file diff --git a/v2.0.2/admin-guide/admin-configuration/index.html b/v2.0.2/admin-guide/admin-configuration/index.html new file mode 100644 index 0000000..daee26d --- /dev/null +++ b/v2.0.2/admin-guide/admin-configuration/index.html @@ -0,0 +1,121 @@ + Configuring zot - zotregistry.dev
Skip to content

Configuring zot

👉 The registry administrator configures zot primarily through settings in the configuration file.

Using the information in this guide, you can compose a configuration file with the settings and features you require for your zot registry server.

💡 Before launching zot with a new configuration, we recommend that you verify the syntax of your configuration as described in Verifying the configuration file.

Configuration file

The configuration file is a JSON or YAML file that contains all configuration settings for zot functions such as:

  • network
  • storage
  • authentication
  • authorization
  • logging
  • metrics
  • synchronization with other registries
  • clustering

The zot service is initiated with the zot serve command followed by the name of a configuration file, as in this example:

zot serve config.json

✏ The instructions and examples in this guide use zot as the name of the zot executable file. The examples do not include the path to the executable file.

When you first build zot or deploy an image or container from the distribution, a basic configuration file config.json is created. This initial file is similar to the following example:

{
+    "distSpecVersion": "1.0.1",
+    "storage": {
+        "rootDirectory": "/tmp/zot"
+    },
+    "http": {
+        "address": "127.0.0.1",
+        "port": "8080"
+    },
+    "log": {
+        "level": "debug"
+    }
+}
+

The configuration file contains the Distribution Specification version (distSpecVersion). The structure and content of other attributes are described in the later sections of this guide.

Extensions

Additional registry features that are not a part of the Distribution Specification are allowed to be added as Extensions.

With a full (not minimal) zot image, the following extension features can be enabled and configured under an extensions attribute in the configuration file as shown in the following example.

{
+  ...
+  "extensions": {
+    "metrics": {},
+    "sync": {},
+    "search": {},
+    "scrub": {},
+    "lint": {},
+    "trust": {},
+    "ui": {}
+  }
+}
+

⚠ The extension features are available only with a full zot image. With a minimal zot image, the extensions section is ignored if present.

The following features are configured under the extensions attribute.

An extension feature is usually enabled by the presence of the feature’s attribute under extensions. An extension feature can then be disabled by either omitting the feature attribute or by including an enable attribute with a value of false.

✏ Two API-only extensions, User Preferences and Mgmt, are not enabled or configured under the extensions section of the configuration file. These API-only extensions are enabled as follows:

  • Mgmt is enabled when the Search extension is enabled.

  • User Preferences is enabled when both the Search and UI extensions are enabled.

Enabling and disabling extensions

Following is an example of enabling or disabling a feature in the extensions section. The scrub feature is enabled in these two configurations:

"extensions": {
+  "scrub": {}
+}
+
"extensions": {
+  "scrub": {
+    "enable": true
+  }
+}
+

The scrub feature is disabled in these two configurations:

"extensions": {
+}
+
"extensions": {
+  "scrub": {
+    "enable": false
+  }
+}
+

Developing custom extensions

New functionality can be added to the zot registry by developing custom extensions for integration into zot. For information about developing extensions, see Developing New Extensions.

Network configuration

Use the http attribute in the configuration file to configure the zot network settings, as shown in the following example.

"http": {
+  "address":"127.0.0.1",
+  "port":"8080",
+  "realm":"zot",
+  "tls": {
+    "cert":"test/data/server.cert",
+    "key":"test/data/server.key"
+  }
+}
+

The following table lists the configurable attributes.

Attribute Description
address The IP address of the zot server.
port The port number of the zot server.
realm The security policy domain defined for the server.
tls The included attributes in this section specify the Transport Layer Security (TLS) settings for the server.
cert The path and filename of the server’s SSL/TLS certificate.
key The path and filename of the server’s registry key.

Storage

Exposing flexibility in storage capabilities is a key tenet for catering to the requirements of varied environments ranging from cloud to on-premises to IoT.

Filesystem storage is configured with the storage attribute in the zot configuration file, as shown in the following simple example.

"storage":{
+  "rootDirectory":"/tmp/zot",
+  "commit": true,
+  "dedupe": true,
+  "gc": true,
+  "gcDelay": "1h",
+  "gcInterval": "24h"
+}
+

With zot, you have the option to store your registry image files either in local filesystem storage or in cloud storage, such as an Amazon Simple Storage Service (S3) bucket.

Local storage

zot can store and serve files from one or more local directories (folders). A minimum of one root directory is required for local hosting, but additional hosted directories can be added. When accessed by HTTP APIs, all directories can appear as a single data store.

✏ Remote filesystems that are mounted and accessible locally such as NFS or fuse are treated as local filesystems.

Remote storage

zot can also store data remotely in the cloud, using the storage APIs of the cloud service. Currently, zot supports only the AWS S3 storage service.

For detailed information about configuring S3 storage, see the AWS S3 documentation and Storage Planning with zot.

Storage features

Commit

Most modern filesystems buffer and flush RAM data to disk after a delay. The purpose of this function is to improve performance at the cost of higher disk memory usage. In embedded devices such as Raspberry Pi, for example, where RAM may be very limited and at a premium, it is desirable to flush data to disk more frequently. The zot storage configuration exposes an option called commit which, when enabled, causes data writes to be committed to disk immediately. This option is disabled by default.

Deduplication

Deduplication is a storage space saving feature wherein only a single copy of specific content is maintained on disk while many different image manifests may hold references to that same content. The deduplication option (dedupe) is also available for supported cloud storage backends.

Upon startup, zot enforces the dedupe status on the existing storage. If the dedupe status upon startup is true, zot deduplicates all blobs found in storage, both local and remote. If the status upon startup is false, zot restores cloud storage blobs to their original state. There is no need for zot to restore local filesystem storage if hard links are used.

Garbage collection

After an image is deleted by deleting an image manifest, the corresponding blobs can be purged to free up space. However, since Distribution Specification APIs are not transactional between blob and manifest lifecycle, care must be taken so as not to put the storage in an inconsistent state. Garbage collection in zot is an inline feature meaning that it is not necessary to take the registry offline. The zot configuration model allows for enabling and disabling garbage collection (gc). The model also allows the configuration of a tunable delay (gcDelay), which can be set depending on client network speeds and the size of blobs.

Scrub

The scrub function, available as an extension, makes it possible to ascertain data validity by computing hashes on blobs periodically and continuously so that any bit rot is caught and reported early.

Configuring storage

For detailed information about configuring local or remote storage and storage features for your zot registry, see Storage Planning with zot.

Security and hardening

Authentication

zot supports authentication by the following methods:

  • TLS mutual authentication

  • Basic local authentication using an htpasswd file

  • LDAP authentication

  • Bearer (OAuth2) authentication using an HTTP Bearer token

For detailed information about configuring authentication for your zot registry, see User Authentication and Authorization with zot.

Identity-based authorization

User identity can be used as an authorization criterion for allowing actions on one or more repository paths. For specific users, you can choose to allow any combination of read, create, update, or delete actions on specific repository paths.

For detailed information about configuring access control policies for your zot registry, see User Authentication and Authorization with zot.

Preventing automated attacks with failure delay

Use the auth and failDelay attributes under http in the configuration file to delay the response to an authentication failure. A delayed response helps to prevent automated attacks. The configuration is shown in the following example.

"http": {
+  "auth": {
+    "failDelay": 5
+  }
+}
+

The failDelay attribute specifies a waiting time, in seconds, before zot sends a failure notification to an authenticating user who has been denied access.

Rate limiting

You can limit the rate of API calls from users by configuring the Ratelimit attribute in the configuration file, as shown in the following example:

"http": {
+    "address": "127.0.0.1",
+    "port": "8080",
+    "Ratelimit": {
+        "Rate": 10,
+        "Methods": [
+            {
+                "Method": "GET",
+                "Rate": 5
+            }
+        ]
+    }
+}
+

In this example, the Rate attribute directly under Ratelimit sets a global rate limit of ten API calls per second. You can optionally override the global limit for specific API Methods. In this example, API GET calls are limited to five per second.

Additional security features

For detailed information about configuring additional security features for your zot registry, see Security Posture.

Monitoring

zot supports a range of monitoring tools including the following:

  • Logging

    Logging for zot operations is configured with the log attribute in the configuration file.

  • Metrics

    Metrics data is available in a Prometheus format. A full zot image with extensions includes a node exporter. A minimal zot image can use an external node exporter such as zxp.

  • Benchmarking

    The zot project includes the zb tool, which allows you to benchmark a zot registry or any other container image registry that conforms to the OCI Distribution Specification.

  • Performance profiling

    Performance profiling capabilities within zot allow a zot administrator to collect and export a range of diagnostic performance data such as CPU intensive function calls, memory allocations, and execution traces. The collected data can then be analyzed using Go tools and a variety of available visualization tools.

When zot is deployed in a Kubernetes setup, a site reliability engineering (SRE) operator can monitor service level indicators (SLI) such as metrics and logs. Metrics will appear in Prometheus using the zot metrics extension, while logs will appear in the Elasticsearch stack (ELK stack) using Filebeat.

For detailed information about the monitoring tools, see Monitoring the registry.

For detailed information about benchmarking, see Benchmarking zot with zb.

For detailed information about performance profiling, see Performance Profiling in zot.

Clustering zot

To ensure high-availability of the registry, zot supports a clustering scheme with stateless zot instances/replicas fronted by a loadbalancer and a shared remote backend storage. This scheme allows the registry service to remain available even if a few replicas fail or become unavailable. Loadbalancing across many zot replicas can also increase aggregate network throughput.

For detailed information about clustering with zot, see zot Clustering.

Syncing and mirroring registries

A zot registry can mirror one or more upstream OCI registries, including popular cloud registries such as Docker Hub and Google Container Registry. If an upstream registry is OCI distribution-spec conformant for pulling images, you can use zot's sync extension feature to implement a downstream mirror, synchronizing OCI images and corresponding artifacts. Synchronization between registries can be implemented by periodic polling of the upstream registry or synchronization can occur on demand, when a user pulls an image from the downstream registry.

As with git, wherein every clone is a full repository, you can configure a local zot instance to be a full OCI mirror registry. This allows for a fully distributed disconnected container image build pipeline.

For detailed information about syncing and mirroring, see OCI Registry Mirroring With zot.

Linting uploaded images

The lint extension can check an uploaded image to enforce the presence of required annotations such as the author or the license.

To configure linting, add the lint attribute under extensions in the configuration file, as shown in the following example:

"extensions": {
+    "lint": {
+      "enable": true,
+      "mandatoryAnnotations": ["annot1", "annot2", "annot3"]
+      }
+  }
+

The following table lists the configurable attributes of the lint extension.

Attribute Description
enable If this attribute is missing, incoming image linting is disabled by default. Linting can be enabled by including this attribute and setting it to true.
mandatoryAnnotations A list of annotations that are required to be present in the image being pushed to the repository.

If the mandatory annotations option is configured when you push an image, linter will verify that the mandatory annotations list present in the configuration is also found in the manifest's annotations list. If any annotations are missing, the push is denied.

Verifying the signatures of uploaded images

The trust extension provides a mechanism to verify image signatures using certificates and public keys.

To enable image signature verification, you must add the trust attribute under extensions in the zot configuration file and enable one or more verification tools, as shown in the following example:

"extensions": {
+  "trust": {
+    "enable": true,
+    "cosign": true,
+    "notation": true
+  }
+}
+

You must also upload public keys (for cosign) or certificates (for notation) that can be used to verify the image signatures.

For detailed information about configuring image signature verification, see Verifying image signatures.

Enabling the registry's graphical user interface

Using the zot graphical user interface (GUI), a user can browse a zot registry for container images and artifacts.

To configure zot's GUI, add the ui attribute under extensions in the configuration file, as shown in the following example:

"extensions": {
+  "ui": {
+    "enable": true
+  }
+}
+

The following table lists the configurable attributes of the ui extension.

Attribute Description
enable If this attribute is missing, the zot GUI is disabled by default. The GUI can be enabled by including this attribute and setting it to true.

Scrubbing the image registry

To check the integrity of the filesystem and the data in the registry, you can schedule a periodic scrub operation. The scrub process traverses the filesystem, verifying that all data blocks are readable. While running, the process may slightly reduce the registry performance.

To enable scrubbing, add the scrub attribute under extensions in the configuration file, as shown in the following example:

"extensions": {
+  "scrub": {
+    "enable": true,
+    "interval": "24h"
+  }
+}
+

The following table lists the configurable attributes for scrubbing the registry.

Attribute Description
enable If this attribute is missing, registry scrubbing is enabled by default. Scrubbing can be disabled by setting this attribute to false.
interval The time interval between periodic scrub operations. This value must be at least two hours (2h).

Scheduling background tasks

Some zot functions, such as garbage collection and registry synchronization, run as background tasks. These tasks are queued and executed by the scheduler.

The scheduler is by default allowed to simultaneously run a maximum number of tasks equal to four times the number of CPUs available to the zot process. For most users, there should be no need to modify this maximum number. If such a need arises, you can configure a new maximum number of simultaneous tasks in the numWorkers property of the scheduler attribute in the configuration file, as shown in the following example.

{
+  "distSpecVersion": "1.1.0-dev",
+  "scheduler": {
+    "numWorkers": 3
+  },
+...
+}
+

Enhanced searching and querying images

While basic searching is always enabled for images in the zot registry, you can enable enhanced registry searching and filtering using graphQL.

Add the search attribute under extensions in the configuration file to enable and configure the enhanced search extension, as shown in the following example.

"extensions": {
+  "search": {
+    "enable": true,
+    "cve": {
+      "updateInterval": "2h"
+    }
+  }
+}
+

The following table lists the configurable attributes for enhanced search.

Attribute Description
enable If this attribute is missing, enhanced search is enabled by default. Enhanced search can be disabled by setting this attribute to false.
cve Extends enhanced search to allow searching of Common Vulnerabilities and Exposures (CVE).
updateInterval Sets the interval at which the searchable database of CVE items is refreshed.

Setting user preferences

The user preferences extension provides an API endpoint for adding configurable user preferences for a repository. This custom extension, not a part of the OCI distribution, is accessible only by authenticated users of the registry. Unauthenticated users are denied access.

The user preferences extension is enabled by default when the search and ui extensions are enabled. There are no other configuration file fields for this extension.

A userprefs API endpoint accepts as a query parameter an action to perform along with any other required parameters for the specified action. The actions currently implemented do not require an HTTP payload, nor do they return any related data other than an HTTP response code.

Current functionality

The current functions implemented by this extension include:

  • Toggling the star (favorites) icon for a repository.
  • Toggling the bookmark icon for a repository.

Toggle repository star

This action sets the repository star property to true if it is false, and to false if it is true.

Action Parameter Parameter Description
toggleStar repo The name of the repository whose star is to be changed

This example toggles a star on a repository named repoName:

PUT
+http://localhost:5000/v2/_zot/ext/userprefs?
+action=toggleStar&repo=repoName
+

Toggle repository bookmark

This action sets the repository bookmark property to true if it is false, and to false if it is true.

Action Parameter Parameter Description
toggleBookmark repo The name of the repository whose bookmark is to be changed

This example toggles a bookmark on a repository named repoName:

PUT
+http://localhost:5000/v2/_zot/ext/userprefs?
+action=toggleBookmark&repo=repoName
+

Verifying the configuration file

Before launching zot, verify the syntax of your configuration file using the following command:

zot verify <configfile>

✏ Verifying the configuration file protects against operator errors and any conflicts arising from zot release version changes.

After verifying your configuration file, you can launch zot with the following command:

zot serve <configfile>


Last update: October 12, 2023
\ No newline at end of file diff --git a/v2.0.2/admin-guide/admin-getting-started/index.html b/v2.0.2/admin-guide/admin-getting-started/index.html new file mode 100644 index 0000000..d696e3e --- /dev/null +++ b/v2.0.2/admin-guide/admin-getting-started/index.html @@ -0,0 +1,19 @@ + Getting Started - zotregistry.dev
Skip to content

Getting Started with zot Administration

👉 This document helps you to deploy an appropriate zot image or to build zot if desired.

After deploying zot, proceed to Configuring zot to choose and configure the features you need.

Installing zot

How to get zot

The zot project is hosted on GitHub at project-zot. From GitHub, you can download zot executable binary images or full source code.

Supported platforms

zot is officially supported on Linux and Apple MacOS platforms, using Intel or ARM processors. However, development should be possible on any platform that supports the golang toolchain.

OS ARCH Platform
linux amd64 Intel-based Linux servers
linux arm64 ARM-based servers and Raspberry Pi4
darwin amd64 Intel-based MacOS
darwin arm64 ARM-based MacOS
freebsd amd64 Intel-based FreeBSD*
freebsd arm64 ARM-based FreeBSD*

* NOTE: While binary images are available for FreeBSD, building container images is not supported at this time.

About binary images

Executable binary zot images are available for multiple platforms and architectures and with full or minimal implementations.

Refer to Released Images for zot for information about available zot images along with information about image variations, image locations, and image naming formats.

Deployment methods

Several options exist for deploying zot:

  • You can launch a zot binary as a container service using a container management tool such as Podman, Docker, or Helm.

  • You can launch zot as a host-level service by downloading a binary image and running it as a systemd service.

  • You can copy or clone the full zot source code and build an image with custom build flags.

Deploying a zot binary image

Executable binary images for supported server platforms and architectures are available from the zot package repository in GitHub.

You can download the appropriate binary image and run it directly on your server, or you can use a container management tool such as Podman, runc, Helm, or Docker to fetch and deploy the image in a container on your server.

💡 For convenience, you can rename the binary image file to simply zot.

Example: Deploying with a container manager

Using a container manager such as Podman, runc, Helm, or Docker, you can install a zot binary image, as in the following examples.

Using podman

podman run -p 5000:5000 ghcr.io/project-zot/zot-linux-amd64:latest
+
+podman run -p 5000:5000 ghcr.io/project-zot/zot-minimal-linux-amd64:latest
+
Click here to view an example of deploying using podman.

Using docker

docker run -p 5000:5000 ghcr.io/project-zot/zot-linux-amd64:latest
+

Each of these example commands pulls a zot binary image from the GitHub Container Registry (ghcr.io) and launches a zot image registry at http://localhost:5000.

Click here to view an example of deploying using docker.

Building zot from source

Prerequisites

Install golang

Follow the golang instructions to install the golang toolchain. After installation, make sure that the path environment variable or your IDE can find the toolchain.

✏ You must use a golang version of at least the minimum specified in go.mod or the build will fail.

Building an executable binary from source

Download or clone the full zot project from GitHub at project-zot. To clone the zot project from GitHub, use this command:

git clone https://github.com/project-zot/zot.git
+

To build zot, execute the make command in the zot directory using the following general syntax:

make OS=os ARCH=architecture {binary | binary-minimal}

  • The operating system and architecture options are listed in the Supported platforms and architectures table. If an option is not specified, the defaults are linux and amd64.

  • The binary option builds the full zot binary image with all extensions.

  • The binary-minimal option builds the minimal distribution-spec conformant zot binary image without extensions, reducing the attack surface.

For example, to build a zot image with extensions for an Intel-based linux server, use the following command:

make OS=linux ARCH=amd64 binary
+

The make command builds an executable image in the zot/bin directory. The original filename of the zot executable image will indicate the build options. For example, the filename of an Intel-based linux minimal image is zot-linux-amd64-minimal.

💡 For convenience, you can rename the binary image file to simply zot.

Building a zot container image from source

with Stacker

Using the settings in stacker.yaml, you can build a container image that runs the latest zot by running the following command:

make binary-stacker
+

with Docker

A sample Dockerfile is provided on the zot project page in GitHub. You can edit the sample file with your specific values, such as the desired operating system, hardware architecture, and full or minimal build, as in this example:

ARG OS=linux
+ARG ARCH=amd64
+
+RUN make COMMIT=$COMMIT OS=$OS ARCH=$ARCH clean binary-minimal
+

Using your edited Dockerfile, you can build a container image that runs the latest zot by running the following command:

make image
+

Deploying the container image

Deploy the image using your container manager, such as Podman, runc, Helm, or Docker, as in these examples:

with Podman

podman run --rm -it -p 5000:5000 -v $(pwd)/registry:/var/lib/registry zot:latest
+

with Docker

docker run --rm -it -p 5000:5000 -v $(pwd)/registry:/var/lib/registry zot:latest
+

A container image built with the sample Dockerfile and deployed with the example command results in a running registry at http://localhost:5000. Registry content is stored at .registry, which is bind mounted to /var/lib/registry in the container. By default, auth is disabled. As part of the build, a YAML configuration file is created at /etc/zot/config.yml in the container.

You can override the configuration file with custom configuration settings in the deployment command and in a local configuration file as shown in this example:

podman run --rm -p 8080:8080 \
+  -v $(pwd)/custom-config.yml:/etc/zot/config.yml \
+  -v $(pwd)/registry:/tmp/zot \
+  zot:latest
+

This command causes the registry to listen on port 8080 and to use /tmp/zot for content storage.

We recommend that, when deploying zot, you also install the command line (zli) and benchmarking (zb) packages.

Launching zot

The zot service is initiated with the zot serve command followed by the name of a configuration file, as in this example:

zot serve config.yml

💡 For convenience, you can rename the binary image file to simply zot.The instructions and examples in this guide use zot as the name of the zot executable file and do not include the path to the executable file.

Next Steps

Configuring zot

You configure zot primarily through adding and modifying settings in the zot configuration file. The configuration file is a JSON or YAML file that contains all configuration settings for zot functions.

When you first build zot or deploy an image or container from the distribution, a basic configuration file config.json is created. You can modify the initial file or you can create a new file.

Follow the instructions in Configuring zot, to compose a configuration file with the settings and features you require for your zot registry server.


Last update: September 13, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/authn-authz/index.html b/v2.0.2/articles/authn-authz/index.html new file mode 100644 index 0000000..820b0b0 --- /dev/null +++ b/v2.0.2/articles/authn-authz/index.html @@ -0,0 +1,188 @@ + Authentication and Authorization - zotregistry.dev
Skip to content

User Authentication and Authorization with zot

👉 A robust set of authentication/authorization options are supported:

  • Authentication

    • TLS, including mTLS
    • Username/password or token-based user authentication
    • LDAP
    • htpasswd
    • OAuth2 with bearer token
  • Authorization

    • Powerful identity-based access controls for repositories or specific repository paths
    • OpenID/OAuth2 social login with Google, GitHub, GitLab, and dex

The zot configuration model supports both authentication and authorization. Authentication credentials allow access to zot HTTP APIs. Authorization policies provide fine-grained control of the actions each authenticated user can perform in the registry.

Authentication

TLS authentication

Because authentication credentials are passed over HTTP, it is imperative that TLS be enabled. You can enable and configure TLS authentication in the zot configuration file, as shown in the following example.

"http": {
+...
+  "tls": {
+    "cert": "/etc/zot/certs/server.cert",
+    "key": "/etc/zot/certs/server.key"
+  }
+

See Mutual TLS authentication for additional information about TLS.

HTTP basic authentication

When basic HTTP authentication is used, the username and password credentials are joined by a colon (:), base64 encoded, and passed in the HTTP Authorization header.

HTTP bearer authentication

To avoid passing the username and password credentials for every HTTP request, a zot client can use bearer token-based authentication. In this method, the client first authenticates with a token server and receives a short-lived token. The client then passes this token in the HTTP Authorization header, specifying Bearer as the authentication scheme.

Configure bearer authentication in the zot configuration file as shown in this example.

"http": {
+...
+  "auth": {
+    "bearer": {
+      "realm": "https://auth.myreg.io/auth/token",
+        "service": "myauth",
+        "cert": "/etc/zot/auth.crt"
+    }
+  }
+

The following table lists the configurable attributes.

Attribute Description
realm A string typically related to the authentication scheme (BASIC and BEARER).
service The name of the authentication service.
cert The path and filename of the server’s SSL/TLS certificate.

Mutual TLS authentication

zot supports basic TLS and password-less mutual TLS authentication (mTLS). Specifying a cacert file in the TLS section of the zot configuration file enables mTLS. The cacert parameter is used to validate the client-side TLS certificates.

"http": {
+...
+  "tls": {
+    "cert": "/etc/zot/certs/server.cert",
+    "key": "/etc/zot/certs/server.key",
+    "cacert": "/etc/zot/certs/ca.cert"
+  }
+

The following table lists the configurable attributes.

Attribute Description
cert The path and filename of the server’s SSL/TLS certificate.
key The path and filename of the server’s registry key.
cacert The path and filename of the server’s cacerts file, which contains trusted certificate authority (CA) certificates.

Preventing automated attacks with failure delay

To help prevent automated attacks, you can add a delayed response to an authentication failure. Configure the failDelay attribute in the configuration file as shown in the following example.

"http": {
+  "auth": {
+    "failDelay": 5
+  }
+}
+

The failDelay attribute specifies a waiting time, in seconds, before zot sends a failure notification to an authenticating user who has been denied access.

Server-side authentication

You can implement server-side authentication for zot using htpasswd or LDAP or both.

✏ When both htpasswd and LDAP configuration are specified, LDAP authentication is given preference. Because htpasswd authentication is strictly local and requires no remote service, htpasswd serves as a fail-safe authentication mechanism should LDAP become unavailable.

LDAP

zot supports integration with an LDAP-based authentication service such as Microsoft Windows Active Directory (AD). Enable and configure LDAP authentication in the zot configuration file, as shown in the following example.

"http": {
+...
+  "auth": {
+    "ldap": {
+      "credentialsFile": "examples/config-ldap-credentials.json",
+      "address": "ldap.example.org",
+      "port": 389,
+      "startTLS": false,
+      "baseDN": "ou=Users,dc=example,dc=org",
+      "userAttribute": "uid",
+      "userGroupAttribute": "memberOf",
+      "bindDN": "cn=ldap-searcher,ou=Users,dc=example,dc=org",
+      "bindPassword": "ldap-searcher-password",
+      "skipVerify": false,
+      "subtreeSearch": true
+    }
+  }
+}
+

The following table lists the configurable attributes for LDAP authentication.

Attribute Description
credentialsFile The path to a file containing the bind credentials for LDAP.
address The IP address or hostname of the LDAP server.
port The port number used by the LDAP service.
startTLS Set to true to enable TLS communication with the LDAP server.
baseDN Starting location within the LDAP directory for performing user searches.
userAttribute Attribute name used to obtain the username.
userGroupAttribute Attribute name used to obtain groups to which a user belongs.
skipVerify Skip TLS verification.
subtreeSearch Set to true to expand the scope for search to include subtrees of the base DN.

To allow for separation of configuration and credentials, the credentials for the LDAP server are specified in a separate file, as shown in the following example.

{
+  "bindDN":"cn=ldap-searcher,ou=Users,dc=example,dc=org",
+  "bindPassword":"ldap-searcher-password"
+}
+

The following table lists the configurable attributes of the LDAP credentials file.

Attribute Description
bindDN Base Distinguished Name for the LDAP search.
bindPassword Password of the bind LDAP user.

htpasswd

Enable and configure htpasswd authentication in the zot configuration file, as shown in the following example.

  1. Create and store an htpasswd file on the server.

    $ htpasswd -bBn <username> <password> >> /etc/zot/htpasswd
    +

    ✏ For strong security, make sure to use the -B option, specifying the bcrypt hashing algorithm. This is the only algorithm supported by zot for htpasswd.

  2. Enable htpasswd authentication and configure the path to the htpasswd authentication in the zot configuration file.

    "http": {
    +...
    +  "auth": {
    +      "htpasswd": {
    +        "path": "/etc/zot/htpasswd"
    +      },
    +

    The path attribute specifies the path and filename of the htpasswd file, which contains user names and hashed passwords.

Authorization

With an access scheme that relies solely on authentication, any authenticated user would be given complete access to the registry. To better control access, zot supports identity-based repository-level access control (authorization) policies. The access control policy is a function of repository, user, and the action being performed on that repository.

Access control policies

Five identity-based types of access control policies are supported:

Policy type Attribute Access allowed
Default defaultPolicy The default policy specifies what actions are allowed if a user is authenticated but does match any user-specific policy.
User-specific users, actions A user-specific policy specifies access and actions for explicitly named users.
Group-specific groups, actions A group-specific policy specifies access and actions for explicitly named groups.
Anonymous anonymousPolicy An anonymous policy specifies what an unauthenticated user is allowed to do. This is an appropriate policy when you want to grant open read-only access to one or more repositories.
Admin adminPolicy The admin policy is a global access control policy that grants privileges to perform actions on any repository.

Access control is organized by repositories, users, and their actions. Most users of a particular repository will have similar access control requirements and can be served by a repository-specific defaultPolicy. Should a user require an exception to the default policy, a user-specific or group-specific override policy can be configured.

With an anonymousPolicy, a repository can allow anonymous actions which do not require user authentication. Finally, one or more users can be designated as administrators, to whom the global adminPolicy applies.

A user's access to a particular repository is evaluated first by whether a user-specific policy exists, then by group-specific policies, and then (in order) by default and admin policies.

A group-specific policy can be applied within any type of access policy, including default or admin policies. The group policy name can also be used with LDAP.

Configuring access control

User identity or group identity can be used as an authorization criterion for allowing actions on one or more repository paths. For specific users, you can choose to allow any combination of read, create, update, or delete actions on specific paths.

When you define policies for specific repository paths, the paths can be specified explicitly or by using glob patterns with simple or recursive wildcards. When a repository path matches more than one path description, authorization is granted based on the policy of the longest (most specific) path matched. For example, if policies are defined for path descriptions ** and repos2/repo, the repos2/repo path will match both ** and repos2/repo descriptions. In this case, the repos2/repo policy will be applied because it is longer.

Note that ** effectively defines the default policy, as it matches any path not matched by any other per-repository policy. To override all other policies, you can specify a global admin policy.

✏ Always include the read action in any policy that you define. The create, update, and delete actions cannot be used without the read action.

Example: Access control configuration

Use the accessControl attribute in the configuration file to define a set of identity-based authorization policies, as shown in the following example.

"http": {
+...
+  "accessControl": {
+    "groups": {
+      "group1": {
+        "users": ["bob", "mary"]
+      },
+      "group2": {
+        "users": ["alice", "mallory", "jim"]
+      }
+    },
+    "repositories": {
+      "**": {
+        "policies": [{
+          "users": ["charlie"],
+          "groups": ["group2"],
+          "actions": ["read", "create", "update"]
+        }],
+        "defaultPolicy": ["read", "create"]
+      },
+      "tmp/**": {
+        "anonymousPolicy": ["read"],
+        "defaultPolicy": ["read", "create", "update"]
+      },
+      "infra/*": {
+        "policies": [{
+            "users": ["alice", "bob"],
+            "actions": ["create", "read", "update", "delete"]
+          },
+          {
+            "users": ["mallory"],
+            "groups": ["group1"],
+            "actions": ["create", "read"]
+          }
+        ],
+        "defaultPolicy": ["read"]
+      },
+      "repos2/repo": {
+        "policies": [{
+            "users": ["bob"],
+            "actions": ["read", "create"]
+          },
+          {
+            "users": ["mallory"],
+            "actions": ["create", "read"]
+          }
+        ],
+        "defaultPolicy": ["read"]
+      }
+    },
+    "adminPolicy": {
+      "users": ["admin"],
+      "actions": ["read", "create", "update", "delete"]
+    }
+  }
+

In this example, five policies are defined:

  • The default policy (**) gives all authenticated users the ability to read or create content, while giving user "charlie" and those in "group2" the additional ability to update content.

  • The policy for tmp/** matches all repositories under tmp recursively and allows all authenticated users to read, create, or update content in those repositories. Unauthenticated users have read-only access to these repositories.

  • The policy for infra/* matches all repositories directly under infra. Separate policies are defined for specific users, along with a default read-only policy for all other users.

  • The policy for repos2/repo matches only that specific repository.

  • An admin policy (adminPolicy) gives the user "admin" global authorization to read, create, update, or delete content in any repository, overriding all other policies.

✏ In releases prior to zot v2.0.0, authorization policies were defined directly under the accessControl key in the zot configuration file. Beginning with v2.0.0, the set of authorization policies are now defined under a new repositories key.

Social login using OpenID/OAuth2

Social login is an authentication/authorization method in which your existing credentials for another site or service can be used to log in to a service such as zot. For example, you can log in to zot using your GitHub account credentials, and zot will contact GitHub to verify your identity using OAuth 2.0 and OpenID Connect (OIDC) protocols.

Several social login providers are supported by zot:

  • github
  • google
  • gitlab
  • oidc (for example, dex)

The following example shows the zot configuration for these providers:

{
+  "http": {
+    "auth": {
+      "openid": {
+        "providers": {
+          "github": {
+            "clientid": <client_id>,
+            "clientsecret": <client_secret>,
+            "scopes": ["read:org", "user", "repo"]
+          },
+          "google": {
+            "issuer": "https://accounts.google.com",
+            "clientid": <client_id>,
+            "clientsecret": <client_secret>,
+            "scopes": ["openid", "email"]
+          },
+          "gitlab": {
+            "issuer": "https://gitlab.com",
+            "clientid": <client_id>,
+            "clientsecret": <client_secret>,
+            "scopes": ["openid", "read_api", "read_user", "profile", "email"]
+          },
+          "oidc": {
+            "issuer": "http://<zot-server>:5556/dex",
+            "clientid": <client_id>,
+            "clientsecret": <client_secret>,
+            "keypath": "",
+            "scopes": ["openid", "profile", "email", "groups"]
+          }
+        }
+      }
+    }
+  }
+}
+

Using Google, GitHub, or GitLab

A client logging into zot by social login must specify a supported OpenID/OAuth2 provider as a URL query parameter. A client logging in using Google, GitHub, or GitLab must additionally specify a callback URL for redirection to a zot page after a successful authentication.

The login URL using Google, GitHub, or GitLab uses the following format:

http://<zot-server>/auth/login?provider=<provider>&callback_ui=<zot-server>/<page>
+

For example, a user logging in to the zot home page using GitHub as the authentication provider sends this URL:

http://zot.example.com:8080/auth/login?provider=github&callback_ui=http://zot.example.com:8080/home
+

Based on the specified provider, zot redirects the login to a provider service with the following URL:

http://<zot-server>/zot/auth/callback/<provider>
+

For the GitHub authentication example:

http://zot.example.com:8080/zot/auth/callback/github
+

✏ If your network policy doesn't allow inbound connections, the callback will not work and this authentication method will fail.

Using dex

dex is an identity service that uses OpenID Connect (OIDC) to drive authentication for client apps, such as zot. While this section shows how to use dex with zot, zot supports other OIDC services as well.

Like zot, dex uses a configuration file for setup. To specify zot as a client in dex, configure a staticClients entry in the dex configuration file with a zot callback, such as the following example in the dex configuration file:

staticClients:
+  - id: zot-client
+    redirectURIs:
+      - 'http://zot.example.com:8080/zot/auth/callback/oidc'
+    name: 'zot'
+    secret: ZXhhbXBsZS1hcHAtc2VjcmV0
+

In the zot configuration file, configure dex as an OpenID auth provider as in the following example:

  "http": {
+    "auth": {
+      "openid": {
+        "providers": {
+          "oidc": {
+            "name": "Corporate SSO",
+            "issuer": "http://<zot-server>:5556/dex",
+            "clientid": "zot-client",
+            "clientsecret": "ZXhhbXBsZS1hcHAtc2VjcmV0",
+            "keypath": "",
+            "scopes": ["openid", "profile", "email", "groups"]
+          }
+        }
+      }
+    }
+  }
+

A user logging in to zot using dex OpenID authentication sends a URL with dex as a URL query parameter, such as the following example:

http://zot.example.com:8080/auth/login?provider=oidc

For detailed information about configuring dex service, see the dex Getting Started documentation.

Using OpenID/OAuth2 when zot is behind a proxy or load balancer

When the zot registry is running behind a proxy or load balancer, you must provide an external URL for OpenID/OAuth2 clients to redirect back to zot. This externalUrl attribute is the URL of the registry, as shown in this example:

  "http": {
+    "address": "0.0.0.0",
+    "port": "8080",
+    "externalUrl": "https://zot.example.com",
+    "auth": {
+      "openid": {
+        "providers": {
+          "github": {
+            "clientid": <client_id>,
+            "clientsecret": <client_secret>,
+            "scopes": ["read:org", "user", "repo"]
+          }
+        }
+      }
+    }
+  }
+

Last update: February 5, 2024
\ No newline at end of file diff --git a/v2.0.2/articles/benchmarking-with-zb/index.html b/v2.0.2/articles/benchmarking-with-zb/index.html new file mode 100644 index 0000000..43db6dd --- /dev/null +++ b/v2.0.2/articles/benchmarking-with-zb/index.html @@ -0,0 +1,54 @@ + Benchmarking with zb - zotregistry.dev
Skip to content

Benchmarking zot with zb

👉 The zb tool is useful for benchmarking OCI registry workloads in scenarios such as the following:

  • comparing configuration changes
  • comparing software versions
  • comparing hardware/deployment environments
  • comparing with other registries

With the zb tool, you can benchmark a zot registry or any other container image registry that conforms to the OCI Distribution Specification published by the Open Container Initiative (OCI).

💡 We recommend installing and benchmarking with zb when you install zot.

How to get zb

The zb project is hosted with zot on GitHub at project-zot. From GitHub, you can download the zb binary or you can build zb from the source. You can also directly run the released docker image.

Supported platforms and architectures

zb is supported for the following operating systems and platform architectures:

OS ARCH Platform
linux amd64 Intel-based Linux servers
linux arm64 ARM-based servers and Raspberry Pi4
darwin amd64 Intel-based MacOS
darwin arm64 ARM-based MacOS

Downloading zb binaries

Download the executable binary for your server platform and architecture under "Assets" on the GitHub zot releases page.

The binary image is named using the target platform and architecture from the Supported platforms and architectures table. For example, the binary for an Intel-based MacOS server is zb-darwin-amd64.

Building zb from source

To build the zb binary, copy or clone the zot project from GitHub and execute the make bench command in the zot directory. Use the same command options that you used to build zot, as shown:

make OS=os ARCH=architecture bench

For example, the following command builds zb for an Intel-based MacOS server:

make OS=darwin ARCH=amd64 bench

In this example, the resulting executable file is zb-darwin-amd64 in the zot/bin directory.

💡 A sample Dockerfile for zb is available at Dockerfile-zb.

Running zb

The original filename of the executable file will reflect the build options, such as zb-linux-amd64. For convenience, you can rename the executable to simply zb.

💡 The instructions and examples in this guide use zb as the name of the executable file.

Usage

To view the usage and options of zb, run the command with the --help option:

bin/zb --help

Command output:

    Usage:
+      zb <url> [flags]
+
+    Flags:
+      -A, --auth-creds string      Use colon-separated BASIC auth creds
+      -c, --concurrency int        Number of multiple requests to make at a time (default 1)
+      -h, --help                   help for zb
+      -o, --output-format string   Output format of test results: stdout (default), json, ci-cd
+      -r, --repo string            Use specified repo on remote registry for test data
+      -n, --requests int           Number of requests to perform (default 1)
+      -s, --src-cidr string        Use specified cidr to obtain ips to make requests from, src-ips and src-cidr are mutually exclusive
+      -i, --src-ips string         Use colon-separated ips to make requests from, src-ips and src-cidr are mutually exclusive
+      -v, --version                Show the version and exit
+      -d, --working-dir string     Use specified directory to store test data
+

Example

The following example executes a benchmark operation using zb.

bin/zb -c 10 -s 127.0.10.0/24 -n 1000 http://localhost:8080

You can also run the released docker image.

docker run --net=host -it ghcr.io/project-zot/zb-linux-amd64:latest -c 10 -n 1000 -s 127.0.10.0/24 http://localhost:8080

Command output:

    Registry URL: http://localhost:8080
+
+    Concurrency Level: 2
+    Total requests:    100
+    Working dir:
+
+    ========
+    Test name:            Get Catalog
+    Time taken for tests: 45.397205ms
+    Complete requests:    100
+    Failed requests:      0
+    Requests per second:  2202.7788
+
+    2xx responses: 100
+
+    min: 402.259µs
+    max: 3.295887ms
+    p50: 855.045µs
+    p75: 971.709µs
+    p90: 1.127389ms
+    p99: 3.295887ms
+
+    ========
+    Test name:            Push Monolith 1MB
+    Time taken for tests: 952.336383ms
+    Complete requests:    100
+    Failed requests:      0
+    Requests per second:  105.00491
+
+    2xx responses: 100
+
+    min: 11.125673ms
+    max: 26.375356ms
+    p50: 18.917253ms
+    p75: 21.753441ms
+    p90: 24.02137ms
+    p99: 26.375356ms
+
+    ...
+

Last update: December 21, 2022
\ No newline at end of file diff --git a/v2.0.2/articles/building-ci-cd-pipeline/index.html b/v2.0.2/articles/building-ci-cd-pipeline/index.html new file mode 100644 index 0000000..1bfae44 --- /dev/null +++ b/v2.0.2/articles/building-ci-cd-pipeline/index.html @@ -0,0 +1,27 @@ + CI/CD Pipeline - zotregistry.dev
Skip to content

Building an OCI-native Container Image CI/CD Pipeline

👉 An OCI-native secure container image build/delivery pipeline using the following tools:

  • stacker for building OCI images

  • zot as a vendor-neutral OCI image registry server

  • skopeo for performing repository interactions

  • cosign for container signing and verification

  • cri-o for deploying container images

  • cosigned for validating container images before deployment

The Open Container Initiative (OCI) is an open governance structure for the express purpose of creating open industry standards around container formats and runtimes.

This document describes a step-by-step procedure towards achieving an OCI-native secure software supply chain using zot in collaboration with other open source tools. The following diagram shows a portion of the CI/CD pipeline.

504568

Build images

stacker is a standalone tool for building OCI images via a declarative yaml format. The output of the build process is a container image in an OCI layout.

example: stacker build command

stacker build -f <stackerfile.yaml>
+

Image registry

zot is a production-ready vendor-neutral OCI image registry server purely based on the OCI Distribution Specification. If stacker is used to build the OCI image, it can also be used to publish the built image to an OCI registry.

example: stacker publish command

stacker publish --url <url> --username <user> --password <password>
+

Alternatively, you can use skopeo, a command line utility that performs various operations on container images and image repositories.

example: skopeo copies an image to a registry

skopeo copy --format=oci oci:<oci-dir>/image:tag \
+  docker://<zot-server>/image:tag
+
Click here to view an example of pushing and pulling an image using skopeo.

Signing images

cosign is a tool that performs container signing, verification, and storage in an OCI registry.

example: cosign generates keys and signs an image in the registry

cosign generate-key-pair
+
+cosign sign --key cosign.key <zot-server>/image:tag
+
Click here to view an example of cosign operations.

Deploying container images

cri-o is an implementation of the Kubernetes Container Runtime Interface (CRI) to enable using OCI compatible runtimes. It is a lightweight alternative to using Docker as the runtime for Kubernetes.

✏ zot is compatible with kubernetes/cri-o using docker:// transport, which is the default.

example: kubelet configuration file

apiVersion: v1
+kind: Pod
+metadata:
+  name: example-pod
+spec:
+  containers:
+  - name: example-container
+    image: <zot-server>/image:tag
+

Container image verification

cosigned is an image admission controller that validates container images before deploying them.

example: install cosigned using Helm

kubectl create namespace cosign-system
+
+kubectl create secret generic mysecret -n \
+  cosign-system --from-file=cosign.pub=./cosign.pub
+
+helm repo add sigstore https://sigstore.github.io/helm-charts
+
+helm repo update
+
+helm install cosigned -n cosign-system sigstore/cosigned \
+  --devel --set cosign.secretKeyRef.name=mysecret
+

Last update: May 18, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/clustering/index.html b/v2.0.2/articles/clustering/index.html new file mode 100644 index 0000000..53d40f7 --- /dev/null +++ b/v2.0.2/articles/clustering/index.html @@ -0,0 +1,76 @@ + Clustering - zotregistry.dev
Skip to content

zot Clustering

👉 High availability of the zot registry is supported by the following features:

  • Stateless zot instances to simplify scale out
  • Bare-metal and Kubernetes deployments

To ensure high-availability of the registry, zot supports a clustering scheme with stateless zot instances/replicas fronted by a loadbalancer and a shared remote backend storage. This scheme allows the registry service to remain available even if a few replicas fail or become unavailable. Loadbalancing across many zot replicas can also increase aggregate network throughput.

504569

Clustering is supported in both bare-metal and Kubernetes environments.

✏ The remote backend storage must be S3 API-compatible.

Bare-metal deployment

Prerequisites

  • A highly-available loadbalancer such as HAProxy configured to direct traffic to zot replicas.

  • Multiple zot replicas as systemd services hosted on multiple hosts or VMs.

  • AWS S3 API-compatible remote backend storage.

Kubernetes deployment

Prerequisites

  • A zot Kubernetes Deployment with required number of replicas.

  • AWS S3 API-compatible remote backend storage.

  • A zot Kubernetes Service.

  • A zot Kubernetes Ingress Gateway if the service needs to be exposed outside.

Implementing stateless zot

zot maintains two types of durable state:

  • the actual image data itself

  • the image metadata in the registry’s cache

In a stateless clustering scheme, the image data is stored in the remote storage backend and the registry cache is disabled by turning off both deduplication and garbage collection.

Ecosystem tools

The OCI Distribution Specification imposes certain rules about the HTTP URI paths to which various ecosystem tools must conform. Consider these rules when setting the HTTP prefixes during loadbalancing and ingress gateway configuration.

Examples

zot supports clustering by using multiple stateless zot replicas with shared S3 storage and an HAProxy (with sticky session) load-balancing traffic to the replicas.

YAML configuration

Click here to view a sample haproxy configuration.
global
+        log /dev/log    local0
+        log /dev/log    local1 notice
+        chroot /var/lib/haproxy
+        maxconn 2000
+        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
+        stats timeout 30s
+        user haproxy
+        group haproxy
+        daemon
+
+        # Default SSL material locations
+        ca-base /etc/ssl/certs
+        crt-base /etc/ssl/private
+
+        # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
+        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
+        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
+
+defaults
+        log     global
+        mode    http
+        option  httplog
+        option  dontlognull
+        timeout connect 5000
+        timeout client  50000
+        timeout server  50000
+        errorfile 400 /etc/haproxy/errors/400.http
+        errorfile 403 /etc/haproxy/errors/403.http
+        errorfile 408 /etc/haproxy/errors/408.http
+        errorfile 500 /etc/haproxy/errors/500.http
+        errorfile 502 /etc/haproxy/errors/502.http
+        errorfile 503 /etc/haproxy/errors/503.http
+        errorfile 504 /etc/haproxy/errors/504.http
+
+frontend zot
+    bind *:8080
+    mode http
+    default_backend zot-cluster
+
+backend zot-cluster
+    mode http
+    balance roundrobin
+    server zot1 127.0.0.1:8081 check
+    server zot2 127.0.0.1:8082 check
+    server zot3 127.0.0.1:8083 check
+

zot S3 configuration

Click here to view a sample zot configuration for S3.
{
+    "distSpecVersion": "1.0.1-dev",
+    "storage": {
+        "rootDirectory": "/tmp/zot",
+        "dedupe": true,
+        "storageDriver": {
+            "name": "s3",
+            "rootdirectory": "/zot",
+            "region": "us-east-2",
+            "bucket": "zot-storage",
+            "secure": true,
+            "skipverify": false
+        },
+        "cacheDriver": {
+            "name": "dynamodb",
+            "endpoint": "http://localhost:4566",
+            "region": "us-east-2",
+            "tableName": "MainTable"
+        }
+    },
+    "http": {
+        "address": "127.0.0.1",
+        "port": "8080"
+    },
+    "log": {
+        "level": "debug"
+    }
+}
+

Last update: May 18, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/graphql/index.html b/v2.0.2/articles/graphql/index.html new file mode 100644 index 0000000..20b1f94 --- /dev/null +++ b/v2.0.2/articles/graphql/index.html @@ -0,0 +1,598 @@ + Using GraphQL for Enhanced Searches - zotregistry.dev
Skip to content

Using GraphQL for Enhanced Searches

👉 A GraphQL backend server within zot's registry search engine provides efficient and enhanced search capabilities. You can submit a GraphQL structured query as an API call or you can use a browser to access the GraphQL Playground, an interactive graphical environment for GraphQL queries.

How to use GraphQL for search queries

GraphQL is a query language for APIs. A GraphQL server, as implemented in zot's registry search engine, executes GraphQL queries that match schema recognized by the server. In response, the server returns a structure containing the requested information. The schema currently recognized by zot are those that correspond to the queries listed in What GraphQL queries are supported.

💡 To learn more about GraphQL, see these resources:

To perform a search, compose a GraphQL structured query for a specific search and deliver it to zot using one of the methods described in the following sections.

For examples of GraphQL queries supported in zot, see Examples of zot searches using GraphQL.

Using the search API directly

You can submit a GraphQL structured query as the HTML data payload in a direct API call using a shell tool such as cURL or Postman. GraphQL queries are sent to the zot search extension API:

/v2/_zot/ext/search
+

The following example submits a zot GraphQL query using cURL:

curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListForCVE (id:\"CVE-2002-1119\") { Results { Name Tags } } }" }' http://localhost:8080/v2/_zot/ext/search
+

The reply to your query is returned as a JSON payload in the HTML response.

Using the GraphQL Playground

✏ The GraphQL Playground feature is available only in a binary-debug zot build or when the zot registry was built with the debug extension label.

The GraphQL Playground is an interactive graphical web interface for GraphQL hosted by the zot registry server.

The GraphQL Playground is reachable by a browser at the following zot API:

/v2/_zot/debug/graphql-playground#
+

For example, if your zot server is located at http://localhost:8080, the GraphQL Playground can be accessed by your browser at this URL:

http://localhost:8080/v2/_zot/debug/graphql-playground#
+

In the GraphQL Playground, you can construct and submit a query structure and you can view the query response in a graphical environment in the browser. You can also inspect the schema.

What GraphQL queries are supported

Supported queries graphQL query Input Output Description
Search images by digest ImageListForDigest digest image list Searches all repositories in the registry and returns list of images that matches given digest (manifest, config or layers)
Search images affected by a given CVE id CVEListForImage CVE id image list Searches the entire registry and returns list of images affected by given CVE
List CVEs for a given image CVEListForImage image CVE list Scans given image and returns list of CVEs affecting the image
List images not affected by a given CVE id ImagesListWithCVEFixed repository, CVE id image list Scans all images in a given repository and returns list of latest (by date) images not affected by the given CVE
Latest image from all repos RepoListWithNewestImage none repo summary list Returns the latest image from all the repos in the registry
List all images with expanded information for a given repository ExpandedRepoInfo repository repo info List expanded repo information for all images in repo, alongside a repo summary
All images in repo ImageList repository image list Returns all images in the specified repo
Global search GlobalSearch query image summary / repo summary / layer summary Will return what's requested in the query argument
Derived image list DerivedImageList image image list Returns a list of images that depend on the image specified in the argument
Base image list BaseImageList image image list Returns a list of images that the specified image depends on
Get details of a specific image Image image image summary Returns details about a specific image
Get referrers of a specific image Referrers repo, digest, type artifact manifests Returns a list of artifacts of given type referring to a specific repo and digests

Examples of zot searches using GraphQL

✏ These examples show only the GraphQL query without details on how to send them to a server. See How to use GraphQL for search queries.

The query structures shown in these examples request all fields allowed by the schema for the particular query type. The schema allows you to request a subset of the data, if desired, omitting any fields that you don't need.

List CVEs of given image

Sample request

{
+  CVEListForImage(
+    image: "alpine:3.17"
+    requestedPage: {limit: 1, offset:1, sortBy: SEVERITY}
+  ) {
+    Tag
+    Page {
+      TotalCount
+      ItemCount
+    }
+    CVEList {
+      Id
+      Title
+      Description
+      Severity
+      PackageList {
+        Name
+        InstalledVersion
+        FixedVersion
+      }
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "CVEListForImage": {
+      "Tag": "3.17",
+      "Page": {
+        "TotalCount": 9,
+        "ItemCount": 1
+      },
+      "CVEList": [
+        {
+          "Id": "CVE-2023-5363",
+          "Title": "openssl: Incorrect cipher key and IV length processing",
+          "Description": "Issue summary: A bug has been identified in the processing of key and\ninitialisation vector (IV) lengths.  This can lead to potential truncation\nor overruns during the initialisation of some symmetric ciphers.\n\nImpact summary: A truncation in the IV can result in non-uniqueness,\nwhich could result in loss of confidentiality for some cipher modes.\n\nWhen calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or\nEVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after\nthe key and IV have been established.  Any alterations to the key length,\nvia the \"keylen\" parameter or the IV length, via the \"ivlen\" parameter,\nwithin the OSSL_PARAM array will not take effect as intended, potentially\ncausing truncation or overreading of these values.  The following ciphers\nand cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.\n\nFor the CCM, GCM and OCB cipher modes, truncation of the IV can result in\nloss of confidentiality.  For example, when following NIST's SP 800-38D\nsection 8.2.1 guidance for constructing a deterministic IV for AES in\nGCM mode, truncation of the counter portion could lead to IV reuse.\n\nBoth truncations and overruns of the key and overruns of the IV will\nproduce incorrect results and could, in some cases, trigger a memory\nexception.  However, these issues are not currently assessed as security\ncritical.\n\nChanging the key and/or IV lengths is not considered to be a common operation\nand the vulnerable API was recently introduced. Furthermore it is likely that\napplication developers will have spotted this problem during testing since\ndecryption would fail unless both peers in the communication were similarly\nvulnerable. For these reasons we expect the probability of an application being\nvulnerable to this to be quite low. However if an application is vulnerable then\nthis issue is considered very serious. For these reasons we have assessed this\nissue as Moderate severity overall.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because\nthe issue lies outside of the FIPS provider boundary.\n\nOpenSSL 3.1 and 3.0 are vulnerable to this issue.",
+          "Severity": "HIGH",
+          "PackageList": [
+            {
+              "Name": "libcrypto3",
+              "InstalledVersion": "3.0.8-r0",
+              "FixedVersion": "3.0.12-r0"
+            },
+            {
+              "Name": "libssl3",
+              "InstalledVersion": "3.0.8-r0",
+              "FixedVersion": "3.0.12-r0"
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
+

Search images affected by a given CVE id

Sample request

{
+  ImageListForCVE(id: "CVE-2023-0464") {
+    Results{
+      RepoName
+      Tag
+      Digest
+      LastUpdated
+      IsSigned
+      Size
+      Vendor
+      DownloadCount
+      Licenses
+      Title
+      Manifests {
+        Digest
+        ConfigDigest
+        Platform {
+          Os
+          Arch
+        }
+      }
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "ImageListForCVE": {
+      "Results": [
+        {
+          "RepoName": "alpine",
+          "Tag": "3.17",
+          "Digest": "sha256:75bfe77c8d5a76b4421cfcebbd62a28ae70d10147578d0cda45820e99b0ef1d8",
+          "LastUpdated": "2023-02-11T04:46:42.558343068Z",
+          "IsSigned": true,
+          "Size": "3375436",
+          "Vendor": "",
+          "DownloadCount": 0,
+          "Licenses": "",
+          "Title": "",
+          "Manifests": [
+            {
+              "Digest": "sha256:75bfe77c8d5a76b4421cfcebbd62a28ae70d10147578d0cda45820e99b0ef1d8",
+              "ConfigDigest": "sha256:6a2bcc1c7b4c9207f791a4512d7f2fa8fc2daeae58dbc51cb2797b05415f082a",
+              "Platform": {
+                "Os": "linux",
+                "Arch": "amd64"
+              }
+            }
+          ]
+        },
+      ]
+    }
+  }
+}
+

List images not affected by a given CVE id

Sample request

{
+  ImageListWithCVEFixed(id: "CVE-2023-0464", image: "ubuntu") {
+    Results {
+      RepoName
+      Tag
+      Digest
+      LastUpdated
+      Manifests {
+        Digest
+        ConfigDigest
+      }
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "ImageListWithCVEFixed": {
+      "Results": [
+        {
+          "RepoName": "ubuntu",
+          "Tag": "kinetic",
+          "Digest": "sha256:1ac35e499e330f6520e80e91b29a55ff298077211f5ed66aff5cb357cca4a28f",
+          "LastUpdated": "2022-10-14T15:28:55.0263968Z",
+          "Manifests": [
+            {
+              "Digest": "sha256:1ac35e499e330f6520e80e91b29a55ff298077211f5ed66aff5cb357cca4a28f",
+              "ConfigDigest": "sha256:824c0269745923afceb9765ae24f5b331bb6fcf2a82f7eba98b3cfd543afb41e"
+            }
+          ]
+        },
+        {
+          "RepoName": "ubuntu",
+          "Tag": "kinetic-20220922",
+          "Digest": "sha256:79eae04a0e32878fef3f8c5f901c32f6704c4a80b7f3fd9d89629e15867acfff",
+          "LastUpdated": "2022-10-14T15:27:41.2144454Z",
+          "Manifests": [
+            {
+              "Digest": "sha256:79eae04a0e32878fef3f8c5f901c32f6704c4a80b7f3fd9d89629e15867acfff",
+              "ConfigDigest": "sha256:15c8dcf63970bb14ea36e41aa001b87d8d31e25a082bf6f659d12489d3e53d90"
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
+

Search images by digest

Sample request

{
+  ImageListForDigest(
+    id: "79eae04a0e32878fef3f8c5f901c32f6704c4a80b7f3fd9d89629e15867acfff"
+  ) {
+    Results{
+      RepoName
+      Tag
+      Title
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "ImageListForDigest": {
+      "Results": [
+        {
+          "RepoName": "ubuntu",
+          "Tag": "kinetic-20220922",
+          "Title": "ubuntu"
+        }
+      ]
+    }
+  }
+}
+

List the latest image across every repository

Sample request

{
+  RepoListWithNewestImage(requestedPage: {limit: 2, offset:0, sortBy: ALPHABETIC_ASC}) {
+    Page {
+      TotalCount
+      ItemCount
+    }
+    Results {
+      Name
+      LastUpdated
+      Size
+      Platforms {
+        Os
+        Arch
+      }
+      NewestImage {
+        Digest
+        Tag
+      }
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "RepoListWithNewestImage": {
+      "Page": {
+        "TotalCount": 30,
+        "ItemCount": 2
+      },
+      "Results": [
+        {
+          "Name": "mariadb",
+          "LastUpdated": "2022-10-18T14:56:33.1993083+03:00",
+          "Size": "124116964",
+          "Platforms": [
+            {
+              "Os": "linux",
+              "Arch": "amd64"
+            }
+          ],
+          "NewestImage": {
+            "Digest": "sha256:49a299f5c4b1af5bc2aa6cf8e50ab5bad85db4d0095745369acfc1934ece99d0",
+            "Tag": "latest"
+          }
+        },
+        {
+          "Name": "tomcat",
+          "LastUpdated": "2022-10-18T14:55:13.8303866+03:00",
+          "Size": "311658063",
+          "Platforms": [
+            {
+              "Os": "linux",
+              "Arch": "amd64"
+            }
+          ],
+          "NewestImage": {
+            "Digest": "sha256:bbc5a3912b568fbfb5912beaf25054f1f407c32a53acae29f19ad97485731a78",
+            "Tag": "jre17"
+          }
+        }
+      ]
+    }
+  }
+}
+

All images in repo

Sample request

{
+  ImageList (repo: "ubuntu") {
+    Results {
+      Tag
+      Digest
+      LastUpdated
+      Size
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "ImageList": {
+      "Results": [
+        {
+          "Tag": "jammy",
+          "Digest": "sha256:f96fcb040c7ee00c037c758cf0ab40638e6ee89b03a9d639178fcbd0e7f96d27",
+          "LastUpdated": "2022-10-14T15:29:18.0325322Z",
+          "Size": "30472739"
+        },
+        {
+          "Tag": "jammy-20221003",
+          "Digest": "sha256:86681debca1719dff33f426a0f5c41792ebc52496c5d78a93b655b8b48fb71b2",
+          "LastUpdated": "2022-10-14T15:29:07.0004587Z",
+          "Size": "30472748"
+        },
+        {
+          "Tag": "kinetic",
+          "Digest": "sha256:1ac35e499e330f6520e80e91b29a55ff298077211f5ed66aff5cb357cca4a28f",
+          "LastUpdated": "2022-10-14T15:28:55.0263968Z",
+          "Size": "27498890"
+        },
+        {
+          "Tag": "kinetic-20220922",
+          "Digest": "sha256:79eae04a0e32878fef3f8c5f901c32f6704c4a80b7f3fd9d89629e15867acfff",
+          "LastUpdated": "2022-10-14T15:27:41.2144454Z",
+          "Size": "27498899"
+        },
+        {
+          "Tag": "latest",
+          "Digest": "sha256:9bc6d811431613bf2fd8bf3565b319af9998fc5c46304022b647c63e1165657c",
+          "LastUpdated": "2022-10-14T15:26:59.6707939Z",
+          "Size": "30472740"
+        },
+        {
+          "Tag": "rolling",
+          "Digest": "sha256:72e75626c5068b9d9a462c4fc80a29787d0cf61c8abc81bfd5ea69f6248d56fc",
+          "LastUpdated": "2022-10-14T15:27:21.2441356Z",
+          "Size": "30472741"
+        }
+      ]
+    }
+  }
+}
+

List all images with expanded information for a given repository

Sample request

{
+  ExpandedRepoInfo(repo: "ubuntu") {
+    Images {
+      Tag
+      Digest
+    }
+    Summary {
+      LastUpdated
+      Size
+      NewestImage {
+        Tag
+        LastUpdated
+        Digest
+      }
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "ExpandedRepoInfo": {
+      "Images": [
+        {
+          "Tag": "jammy",
+          "Digest": "sha256:f96fcb040c7ee00c037c758cf0ab40638e6ee89b03a9d639178fcbd0e7f96d27"
+        },
+        {
+          "Tag": "jammy-20221003",
+          "Digest": "sha256:86681debca1719dff33f426a0f5c41792ebc52496c5d78a93b655b8b48fb71b2"
+        },
+        {
+          "Tag": "kinetic",
+          "Digest": "sha256:1ac35e499e330f6520e80e91b29a55ff298077211f5ed66aff5cb357cca4a28f"
+        },
+        {
+          "Tag": "kinetic-20220922",
+          "Digest": "sha256:79eae04a0e32878fef3f8c5f901c32f6704c4a80b7f3fd9d89629e15867acfff"
+        },
+        {
+          "Tag": "rolling",
+          "Digest": "sha256:72e75626c5068b9d9a462c4fc80a29787d0cf61c8abc81bfd5ea69f6248d56fc"
+        },
+        {
+          "Tag": "latest",
+          "Digest": "sha256:9bc6d811431613bf2fd8bf3565b319af9998fc5c46304022b647c63e1165657c"
+        }
+      ],
+      "Summary": {
+        "LastUpdated": "2022-10-14T15:29:18.0325322Z",
+        "Size": "58146896",
+        "NewestImage": {
+          "Tag": "jammy",
+          "LastUpdated": "2022-10-14T15:29:18.0325322Z",
+          "Digest": "sha256:f96fcb040c7ee00c037c758cf0ab40638e6ee89b03a9d639178fcbd0e7f96d27"
+        }
+      }
+    }
+  }
+}
+

Sample request

{
+  GlobalSearch(query: "ubuntu:latest") {
+    Page {
+      ItemCount
+      TotalCount
+    }
+    Images {
+      RepoName
+      Tag
+      LastUpdated
+      Manifests {
+        Digest
+        Layers {
+          Size
+          Digest
+        }
+      }
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "GlobalSearch": {
+      "Page": {
+        "ItemCount": 1,
+        "TotalCount": 1
+      },
+      "Images": [
+        {
+          "RepoName": "ubuntu",
+          "Tag": "latest",
+          "LastUpdated": "2022-10-14T15:26:59.6707939Z",
+          "Manifests": [
+            {
+              "Digest": "sha256:9bc6d811431613bf2fd8bf3565b319af9998fc5c46304022b647c63e1165657c",
+              "Layers": [
+                {
+                  "Size": "30428928",
+                  "Digest": "sha256:cf92e523b49ea3d1fae59f5f082437a5f96c244fda6697995920142ff31d59cf"
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
+

Sample request

{
+  GlobalSearch(query: "") {
+    Repos {
+      Name
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "GlobalSearch": {
+      "Repos": [
+        {
+          "Name": "centos"
+        },
+        {
+          "Name": "ubuntu"
+        }
+      ]
+    }
+  }
+}
+

Search derived images

Sample query

{
+  DerivedImageList(image: "ubuntu:latest", requestedPage: {offset: 0, limit: 10}) {
+    Page {
+      TotalCount
+      ItemCount
+    }
+    Results {
+      RepoName
+      Tag
+      LastUpdated
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "DerivedImageList": {
+      "Page": {
+        "TotalCount": 9,
+        "ItemCount": 9
+      },
+      "Results": [
+        {
+          "RepoName": "mariadb",
+          "Tag": "latest",
+          "LastUpdated": "2022-10-18T14:56:33.1993083+03:00"
+        },
+        {
+          "RepoName": "maven",
+          "Tag": "latest",
+          "LastUpdated": "2022-10-14T18:30:12.0929807+03:00"
+        },
+        {
+          "RepoName": "tomcat",
+          "Tag": "latest",
+          "LastUpdated": "2022-10-18T14:50:09.7229959+03:00"
+        },
+        {
+          "RepoName": "tomcat",
+          "Tag": "jre17",
+          "LastUpdated": "2022-10-18T14:55:13.8303866+03:00"
+        },
+        {
+          "RepoName": "tomcat",
+          "Tag": "jre17-temurin",
+          "LastUpdated": "2022-10-18T14:54:46.4133521+03:00"
+        },
+        {
+          "RepoName": "tomcat",
+          "Tag": "jre17-temurin-jammy",
+          "LastUpdated": "2022-10-18T14:51:12.235475+03:00"
+        }
+      ]
+    }
+  }
+}
+

Search base images

Sample query

{
+  BaseImageList(image: "mariadb:latest", requestedPage: {offset: 0, limit: 10}) {
+    Page {
+      TotalCount
+      ItemCount
+    }
+    Results {
+      RepoName
+      Tag
+      LastUpdated
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "BaseImageList": {
+      "Page": {
+        "TotalCount": 4,
+        "ItemCount": 4
+      },
+      "Results": [
+        {
+          "RepoName": "ubuntu",
+          "Tag": "jammy",
+          "LastUpdated": "2022-10-14T18:29:18.0325322+03:00"
+        },
+        {
+          "RepoName": "ubuntu",
+          "Tag": "jammy-20221003",
+          "LastUpdated": "2022-10-14T18:29:07.0004587+03:00"
+        },
+        {
+          "RepoName": "ubuntu",
+          "Tag": "latest",
+          "LastUpdated": "2022-10-14T18:26:59.6707939+03:00"
+        },
+        {
+          "RepoName": "ubuntu",
+          "Tag": "rolling",
+          "LastUpdated": "2022-10-14T18:27:21.2441356+03:00"
+        }
+      ]
+    }
+  }
+}
+

Get details of a specific image

Sample query

{
+  Image(image: "mariadb:latest") {
+    RepoName
+    Tag
+    LastUpdated
+    Digest
+    Description
+  }
+}
+

Sample response

{
+  "data": {
+    "Image": {
+      "RepoName": "mariadb",
+      "Tag": "latest",
+      "LastUpdated": "2022-10-18T14:56:33.1993083+03:00",
+      "Digest": "sha256:49a299f5c4b1af5bc2aa6cf8e50ab5bad85db4d0095745369acfc1934ece99d0",
+      "Description": "MariaDB Server is a high performing open source relational database, forked from MySQL."
+    }
+  }
+}
+

Get referrers of a specific image

Sample query

{
+  Referrers(
+    repo: "golang"
+    digest: "sha256:fed08b0eaea00aab17f82ecbb78675919d216c72eea985581758191f694aeaf7"
+    type: "application/vnd.example.icecream.v1"
+  ) {
+    MediaType
+    ArtifactType
+    Digest
+    Annotations {
+      Key
+      Value
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "Referrers": [
+      {
+        "MediaType": "application/vnd.oci.artifact.manifest.v1+json",
+        "ArtifactType": "application/vnd.example.icecream.v1",
+        "Digest": "sha256:be7a3d01c35a2cf53c502e9dc50cdf36b15d9361c81c63bf319f1d5cbe44ab7c",
+        "Annotations": [
+          {
+            "Key": "format",
+            "Value": "oci"
+          },
+          {
+            "Key": "demo",
+            "Value": "true"
+          }
+        ]
+      },
+      {
+        "MediaType": "application/vnd.oci.artifact.manifest.v1+json",
+        "ArtifactType": "application/vnd.example.icecream.v1",
+        "Digest": "sha256:d9ad22f41d9cb9797c134401416eee2a70446cee1a8eb76fc6b191f4320dade2",
+        "Annotations": [
+          {
+            "Key": "demo",
+            "Value": "true"
+          },
+          {
+            "Key": "format",
+            "Value": "oci"
+          }
+        ]
+      }
+    ]
+  }
+}
+

Last update: November 15, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/immutable-tags/index.html b/v2.0.2/articles/immutable-tags/index.html new file mode 100644 index 0000000..b030e74 --- /dev/null +++ b/v2.0.2/articles/immutable-tags/index.html @@ -0,0 +1,23 @@ + Immutable Image Tags - zotregistry.dev
Skip to content

Immutable Image Tags

👉 Immutable image tag support is achieved by leveraging authorization policies.

It is considered best practice to avoid changing the content once a software version has been released. While zot does not have an explicit configuration flag to make image tags immutable, the same effect can be achieved with authorization as follows.

Immutable For All Users

By setting the defaultPolicy to "read" and "create" for a particular repository, images can be pushed (once) and pulled but further updates are rejected.

{
+...
+  "repositories": {
+    "**": {
+      "defaultPolicy": ["read", "create"]
+    }
+  }
+...
+}
+

Immutable With Overrides

As in the example above, with defaultPolicy set to "read" and "create" for a particular repository, images can be pushed (once) and pulled, but further updates are rejected. Exceptions can be made for some users, and user-specific policies can be added to allow "update" operations as shown below.

{
+...
+  "repositories": {
+    "**": {
+      "policies": [{
+        "users": ["alice", "bob"],
+        "actions": ["read", "create", "update"]
+      }],
+      "defaultPolicy": ["read", "create"]
+    }
+  }
+...
+}
+

Last update: March 13, 2024
\ No newline at end of file diff --git a/v2.0.2/articles/kind-deploy/index.html b/v2.0.2/articles/kind-deploy/index.html new file mode 100644 index 0000000..79d12ea --- /dev/null +++ b/v2.0.2/articles/kind-deploy/index.html @@ -0,0 +1,124 @@ + Using kind for Deployment Testing - zotregistry.dev
Skip to content

Using kind for Deployment Testing

👉 Use kind to try out zot deployment with Kubernetes.

This article describes how to create a kind cluster that includes a local zot registry.

Deploying the cluster and registry

The procedure described installs a kind cluster with a zot registry at localhost:5001 and then loads and runs a "hello" app to test the installation. Although the procedure is given as a series of steps, you can find a complete shell script to perform these steps at the end of this article.

✏ This article is based on Create A Cluster And Registry, which you can find on the kind website.

Step 1: Prepare the environment

The following packages must be installed:

  • docker
  • kubernetes
  • kind
  • containerd
  • skopeo

Execute the following shell commands to set environment variables.

set -o errexit
+
+# set no_proxy if applicable
+if [ ! -z "${no_proxy}" ]; then 
+  echo "Updating no_proxy environment variables";
+  export no_proxy=${no_proxy},kind-registry;
+  export NO_PROXY=${no_proxy};
+fi
+

Step 2: Create a registry container

Create a kind-registry container, pulling a zot binary from the GitHub Container Registry (ghcr.io).

✏ This example pulls zot-minimal-linux-amd64:latest,
a minimal (no extensions) zot image for an AMD-based linux server.

Other available images are described at the zot releases page in GitHub.
You can also specify a release by replacing latest with an available release number.

# create registry container unless it already exists
+reg_name='kind-registry'
+reg_port='5001'
+if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then
+  docker run \
+    -d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" \
+    ghcr.io/project-zot/zot-minimal-linux-amd64:latest
+fi
+

Step 3: Create the kind cluster

Create a cluster with the local registry enabled.

# enable the local registry in containerd
+cat <<EOF | kind create cluster --config=-
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+containerdConfigPatches:
+- |-
+  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${reg_port}"]
+    endpoint = ["http://${reg_name}:5000"]
+EOF
+

Step 4: Connect the registry to the cluster network

Connect the registry to the "kind" network so that it can communicate with other resources in the same network.

# check whether already connected to the network
+if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' \
+"${reg_name}")" = 'null' ]; then
+  docker network connect "kind" "${reg_name}"
+fi
+

Step 5: Document the local registry

Create a ConfigMap that specifies how to interact with the local registry. This ConfigMap follows the KEP-1755 Standard for communicating a local registry.

cat <<EOF | kubectl apply -f -
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: local-registry-hosting
+  namespace: kube-public
+data:
+  localRegistryHosting.v1: |
+    host: "localhost:${reg_port}"
+    help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
+EOF
+

Step 6: Deploy and test

Use skopeo to copy (pull) a "hello" app from the Google Container Registry (gcr.io) into the new zot registry. Using kubectl, deploy the app from the new local zot registry as "hello-server" and monitor the deployment for initial availability.

# copy an image
+skopeo copy --format=oci --dest-tls-verify=false \
+docker://gcr.io/google-samples/hello-app:1.0 \
+docker://localhost:5001/hello-app:1.0
+
+# deploy the image
+kubectl create deployment hello-server --image=localhost:5001/hello-app:1.0
+
+# check for availability
+echo "Waiting for deployment/hello-server to be ready ..."
+kubectl wait deployment -n default hello-server \
+  --for condition=Available=True --timeout=90s
+

Clean up

To clean up after testing, run the following commands to delete the kind cluster and registry.

kind delete cluster
+docker stop kind-registry
+docker rm kind-registry
+

Reference: A complete script

The following script executes all of the preceding steps.

Click here to view the entire script
#!/bin/sh
+set -o errexit
+
+# Reference: https://kind.sigs.k8s.io/docs/user/local-registry/
+
+# set no_proxy if applicable
+if [ ! -z "${no_proxy}" ]; then 
+  echo "Updating no_proxy env var";
+  export no_proxy=${no_proxy},kind-registry;
+  export NO_PROXY=${no_proxy};
+fi
+
+# create registry container unless it already exists
+reg_name='kind-registry'
+reg_port='5001'
+if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then
+  docker run \
+    -d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" \
+    ghcr.io/project-zot/zot-minimal-linux-amd64:latest
+fi
+
+# create a cluster with the local registry enabled in containerd
+cat <<EOF | kind create cluster --config=-
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+containerdConfigPatches:
+- |-
+  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${reg_port}"]
+    endpoint = ["http://${reg_name}:5000"]
+EOF
+
+# connect the registry to the cluster network if not already connected
+if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' "${reg_name}")" = 'null' ]; then
+  docker network connect "kind" "${reg_name}"
+fi
+
+# https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry
+#
+# document the local registry
+cat <<EOF | kubectl apply -f -
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: local-registry-hosting
+  namespace: kube-public
+data:
+  localRegistryHosting.v1: |
+    host: "localhost:${reg_port}"
+    help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
+EOF
+
+# copy an image
+skopeo copy --format=oci --dest-tls-verify=false docker://gcr.io/google-samples/hello-app:1.0 docker://localhost:5001/hello-app:1.0
+
+# deploy the image
+kubectl create deployment hello-server --image=localhost:5001/hello-app:1.0
+
+# check for availability
+echo "Waiting for deployment/hello-server to be ready ..."
+kubectl wait deployment -n default hello-server --for condition=Available=True --timeout=90s
+
+# cleanup
+echo "Press a key to begin cleanup ..."
+read KEYPRESS
+kind delete cluster
+docker stop kind-registry
+docker rm kind-registry
+

Last update: September 13, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/mirroring/index.html b/v2.0.2/articles/mirroring/index.html new file mode 100644 index 0000000..1f386f4 --- /dev/null +++ b/v2.0.2/articles/mirroring/index.html @@ -0,0 +1,248 @@ + Mirroring - zotregistry.dev
Skip to content

OCI Registry Mirroring With zot

👉 A zot registry can mirror one or more upstream OCI registries, including popular cloud registries such as Docker Hub and Google Container Registry (gcr.io).

A key use case for zot is to act as a mirror for upstream registries. If an upstream registry is OCI distribution-spec conformant for pulling images, you can use zot's sync feature to implement a downstream mirror, synchronizing OCI images and corresponding artifacts. Because synchronized images are stored in zot's local storage, registry mirroring allows for a fully distributed disconnected container image build pipeline. Container image operations terminate in local zot storage, which may reduce network latency and costs.

⚠ Because zot is a OCI-only registry, any upstream image stored in the Docker image format is converted to OCI format when downloading to zot. In the conversion, some non-OCI attributes may be lost. Signatures, for example, are removed due to the incompatibility between formats.

Mirroring modes

For mirroring an upstream registry, two common use cases are a fully mirrored or a pull through (on-demand) cache registry.

As with git, wherein every clone is a full repository, you can configure your local zot instance to be a fully mirrored OCI registry. For this mode, configure zot for synchronization by periodic polling, not on-demand. Zot copies and caches a full copy of every image on the upstream registry, updating the cache whenever polling discovers a change in content or image version at the upstream registry.

For a pull through cache mirrored registry, configure zot for on-demand synchronization. When an image is first requested from the local zot registry, the image is downloaded from the upstream registry and cached in local storage. Subsequent requests for the same image are served from zot's cache. Images that have not been requested are not downloaded. If a polling interval is also configured, zot periodically polls the upstream registry for changes, updating any cached images if changes are detected.

✏ Because Docker Hub rate-limits pulls and does not support catalog listing, do not use polled mirroring with Docker Hub. Use only on-demand mirroring with Docker Hub.

Migrating or updating a registry using mirroring

Mirroring zot using the sync feature allows you to easily migrate a registry. In situations such as the following, zot mirroring provides an easy solution.

  • Migrating an existing zot or non-zot registry to a new location.

    Provided that the source registry is OCI-compliant for image pulls, you can mirror the registry to a new zot registry, delete the old registry, and reroute network traffic to the new registry.

  • Updating (or downgrading) a zot registry.

    To minimize downtime during an update, or to avoid any incompatibilities between zot releases that would preclude an in-place update, you can bring up a new zot registry with the desired release and then migrate from the existing registry.

To ensure a complete migration of the registry contents, set a polling interval in the configuration of the new zot registry and set prefix to **, as shown in this example:

  {
+    "urls": [
+        "https://registry1:5000"
+    ],
+    "pollInterval": "12h",
+    "onDemand": true,
+    "content": [
+        {
+            "prefix": "**"
+        }
+    ]
+  }
+

Basic configuration for mirroring with sync

The sync feature of zot is an extension of the OCI-compliant registry implementation. You can configure the sync feature under the extensions section of the zot configuration file, as shown in this example:

  "extensions": {
+    "sync": {
+      "credentialsFile": "./examples/sync-auth-filepath.json",
+      "registries": [
+        {
+          "urls": [
+            "https://registry1:5000"
+          ],
+          "onDemand": false,
+          "pollInterval": "6h",
+          "tlsVerify": true,
+          "certDir": "/home/user/certs",
+          "maxRetries": 3,
+          "retryDelay": "5m", 
+          "onlySigned": true,
+          "content": [
+            {
+              "prefix": "/repo2/repo",
+              "tags": {
+                "regex": "4.*",
+                "semver": true
+              }
+              "destination": "/repo2",
+              "stripPrefix": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+

The following table lists the configurable attributes for the sync feature:

Attribute Description

credentialsFile

The location of a local file containing credentials for other registries, as in the following example:

{
  "127.0.0.1:8080": {
    "username": "user",
    "password": "pass"
  },
    "registry2:5000": {
    "username": "user2",
    "password": "pass2"
  }
}

urls

A list of one or more URLs to an upstream image registry. If the main URL fails, the sync process will try the next URLs in the listed order.

onDemand

  • false: Pull all images not found in the local registry.

  • true: Pull any image not found in the local registry only when the image is requested by a user.

pollInterval

The period in seconds between polling of a remote registry. If no value is specified, no periodic polling will occur. If a value is set and the content attributes are configured, periodic synchronization is enabled and will run at the specified value.

Note: Because Docker Hub rate-limits pulls and does not support catalog listing, do not use polled mirroring with Docker Hub. Use only onDemand mirroring with Docker Hub.

tlsVerify

  • false: TLS will not be verified.

  • true: (Default) The TLS connection to the destination registry will be verified.

certDir

If a path is specified, use certificates (*.crt, *.cert, *.key files) at this path when connecting to the destination registry or daemon. If no path is specified, use the default certificates directory.

maxRetries

The maximum number of retries if an error occurs during either an on-demand or periodic synchronization. If no value is specified, no retries will occur.

retryDelay

The interval in seconds between retries. This attribute is mandatory when maxRetries is configured.

onlySigned

  • false: Synchronize signed or unsigned images.

  • true: Synchronize only signed images (either notary or cosign).

content

The included attributes in this section specify which content will be pulled. If this section is not populated, periodic polling will not occur. The included attributes can also filter which on-demand images are pulled.

  prefix

On the remote registry, the path from which images will be pulled. This path can be a string that exactly matches the remote path, or it can be a glob pattern. For example, the path can include a wildcard (*) or a recursive wildcard (**).

  tags

The included attributes in this optional section specify how remote images will be selected for synchronization based on image tags.

  tags.regex

Specifies a regular expression for matching image tags. Images whose tags do not match the expression are not pulled.

  tags.semver

Specifies whether image tags are to be filtered by semantic versioning (semver) compliance.

  • false: Do not filter by semantic versioning.

  • true: Filter by semantic versioning.

  destination

Specifies the local path in which pulled images are to be stored.

  stripPrefix

Specifies whether the prefix path from the remote registry will be retained or replaced when the image is stored in the zot registry.

  • false: Retain the source prefix, append it to the destination path.

  • true: Remove the source prefix.

    Note: If the source prefix was specified with meta-characters (such as **), only the prefix segments that precede the meta-characters are removed. Any remaining path segments are appended to the destination path.

Configuration examples for mirroring

Example: Multiple repositories with polled mirroring

The following is an example of sync configuration for mirroring multiple repositories with polled mirroring.

"sync": {
+  "enable": true,
+  "credentialsFile": "./examples/sync-auth-filepath.json",
+  "registries": [
+    {
+      "urls": ["https://registry1:5000"],
+      "onDemand": false,
+      "pollInterval": "6h",
+      "tlsVerify": true,
+      "certDir": "/home/user/certs",
+      "maxRetries": 3,
+      "retryDelay": "5m",
+      "onlySigned": true,
+      "content": [
+        {
+          "prefix": "/repo1/repo",
+          "tags": {
+            "regex": "4.*",
+            "semver": true
+          }
+        },
+        {
+          "prefix": "/repo2/repo",
+          "destination": "/repo2",
+          "stripPrefix": true
+        },
+        {
+          "prefix": "/repo3/repo"
+        }
+      ]
+    }
+  }
+

The configuration in this example will result in the following behavior:

  • Only signed images (notation and cosign) are synchronized.
  • The sync communication is secured using certificates in certDir.
  • This registry synchronizes with upstream registry every 6 hours.
  • On-demand mirroring is disabled.
  • Based on the content filtering options, this registry synchronizes these images:
    • From /repo1/repo, images with tags that begin with "4." and are semver compliant.
      Files are stored locally in /repo1/repo on localhost.
    • From /repo2/repo, images with all tags.
      Because stripPrefix is enabled, files are stored locally in /repo2. For example, docker://upstream/repo2/repo:v1 is stored as docker://local/repo2:v1.
    • From /repo3/repo, images with all tags.
      Files are stored locally in /repo3/repo.

Example: Multiple registries with on-demand mirroring

The following is an example of sync configuration for mirroring multiple registries with on-demand mirroring.

{
+  "distSpecVersion": "1.0.1",
+  "storage": {
+    "rootDirectory": "/tmp/zot",
+    "gc": true
+  },
+  "http": {
+    "address": "0.0.0.0",
+    "port": "8080"
+  },
+  "log": {
+    "level": "debug"
+  },
+  "extensions": {
+    "sync": {
+      "enable": true,
+      "registries": [
+        {
+          "urls": ["https://k8s.gcr.io"],
+          "content": [
+            {
+              "prefix": "**", 
+              "destination": "/k8s-images"
+            }
+          ],
+          "onDemand": true,
+          "tlsVerify": true
+        },
+        {
+          "urls": ["https://docker.io/library"],
+          "content": [
+            {
+              "prefix": "**", 
+              "destination": "/docker-images"
+            }
+          ],
+          "onDemand": true,
+          "tlsVerify": true
+        }
+      ]
+    }
+  }
+}
+

With this zot configuration, the sync behavior is as follows:

  1. This initial user request for content from the zot registry:
    skopeo copy --src-tls-verify=false docker://localhost:8080/docker-images/alpine <dest>
    causes zot to synchronize the content with the docker.io registry:
        docker.io/library/alpine:latest
    to the zot registry:
        localhost:8080/docker-images/alpine:latest
    before delivering the content to the requestor at <dest>.

  2. This initial user request for content from the zot registry:
    skopeo copy --src-tls-verify=false docker://localhost:8080/k8s-images/kube-proxy:v1.19.2 <dest>
    causes zot to synchronize the content with the gcr.io registry:
        k8s.gcr.io/kube-proxy:v1.19.2
    to the zot registry:
        localhost:8080/k8s-images/kube-proxy:v1.19.2
    before delivering the content to the requestor at <dest>.

You can use this command:
     curl http://localhost:8080/v2/_catalog
to display the local repositories:

  {
+    "repositories":[
+      "docker-images/alpine",
+      "k8s-images/kube-proxy"
+    ]
+  }
+

Example: Multiple registries with mixed mirroring modes

The following is an example of a zot configuration file for mirroring multiple upstream registries.

{
+  "distSpecVersion": "1.1.0-dev",
+  "storage": {
+    "rootDirectory": "/tmp/zot"
+  },
+  "http": {
+    "address": "127.0.0.1",
+    "port": "8080"
+  },
+  "log": {
+    "level": "debug"
+  },
+  "extensions": {
+    "sync": {
+      "enable": true,
+      "credentialsFile": "./examples/sync-auth-filepath.json",
+      "registries": [
+        {
+          "urls": [
+            "https://registry1:5000"
+          ],
+          "onDemand": false,
+          "pollInterval": "6h",
+          "tlsVerify": true,
+          "certDir": "/home/user/certs",
+          "maxRetries": 3,
+          "retryDelay": "5m",
+          "onlySigned": true,
+          "content": [
+            {
+              "prefix": "/repo1/repo",
+              "tags": {
+                "regex": "4.*",
+                "semver": true
+              }
+            },
+            {
+              "prefix": "/repo1/repo",
+              "destination": "/repo",
+              "stripPrefix": true
+            },
+            {
+              "prefix": "/repo2/repo"
+            }
+          ]
+        },
+        {
+          "urls": [
+            "https://registry2:5000",
+            "https://registry3:5000"
+          ],
+          "pollInterval": "12h",
+          "tlsVerify": false,
+          "onDemand": false,
+          "content": [
+            {
+              "prefix": "/repo2",
+              "tags": {
+                "semver": true
+              }
+            }
+          ]
+        },
+        {
+          "urls": [
+            "https://docker.io/library"
+          ],
+          "onDemand": true,
+          "tlsVerify": true,
+          "maxRetries": 6,
+          "retryDelay": "5m"
+        }
+      ]
+    }
+  }
+}
+

Example: Support for subpaths in local storage

{
+  "distSpecVersion": "1.0.1",
+  "storage": {
+    "subPaths":{
+      "/kube-proxy":{
+        "rootDirectory": "/tmp/kube-proxy",
+        "dedupe": true,
+        "gc": true
+       }
+     },
+    "rootDirectory": "/tmp/zot",
+    "gc": true
+  },
+  "http": {
+    "address": "0.0.0.0",
+    "port": "8080"
+  },
+  "log": {
+    "level": "debug"
+  },
+  "extensions": {
+    "sync": {
+      "enable": true,
+      "registries": [
+        {
+          "urls": ["https://k8s.gcr.io"],
+          "content": [
+            {
+              "destination": "/kube-proxy", 
+              "prefix": "**"
+            }
+          ],
+          "onDemand": true,
+          "tlsVerify": true,
+          "maxRetries": 2,
+          "retryDelay": "5m"
+        }
+      ]
+    }
+  }
+}
+
With this zot configuration, the sync behavior is as follows:

  • This user request for content from the zot registry:
    skopeo copy --src-tls-verify=false docker://localhost:8080/kube-proxy/kube-proxy:v1.19.2 <dest>
    causes zot to synchronize the content with this remote registry:
        k8s.gcr.io/kube-proxy:v1.19.2
    to the zot registry:
        localhost:8080/kube-proxy/kube-proxy:v1.19.2
    before delivering the content to the requestor at <dest>.

You can use this command:
     curl http://localhost:8080/v2/_catalog
to display the local repositories:

  {
+    "repositories":[
+      "docker-images/alpine",
+      "k8s-images/kube-proxy",
+      "kube-proxy/kube-proxy"
+    ]
+  }
+

In zot storage, the requested content is located here:
    /tmp/zot/kube-proxy/kube-proxy/kube-proxy/
This subpath is created from the following path components:

  • /tmp/zot is the rootDirectory of the zot registry
  • kube-proxy is the rootDirectory of the storage subpath
  • kube-proxy is the sync destination parameter
  • kube-proxy is the repository name

Last update: September 13, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/monitoring/index.html b/v2.0.2/articles/monitoring/index.html new file mode 100644 index 0000000..65cfd35 --- /dev/null +++ b/v2.0.2/articles/monitoring/index.html @@ -0,0 +1,27 @@ + Monitoring - zotregistry.dev
Skip to content

Monitoring the registry

👉 zot supports a range of monitoring tools including logging, metrics, and benchmarking.

The following sections describe how to configure logging and monitoring with zot. You can use zot's benchmarking tool to test your configuration and deployment, as described in Benchmarking zot with zb.

Logging

Logging for zot operations is configured with the log attribute in the configuration file, as shown in the following example.

"log":{
+  "level":"debug",
+  "output":"/tmp/zot.log",
+  "audit": "/tmp/zot-audit.log"
+}
+

The following table lists the configurable attributes.

Attribute Description

level

The minimum level for logged events. The levels are:
panic, fatal, error, warn, info, debug, and trace.

output

The filesystem path for the log output file. The default is stdout.

audit

(Optional) If a filesystem path is specified for audit logging, an audit log is enabled and will be stored at the specified path.

Metrics

The available methods for collecting metrics varies depending on whether your zot installation is a minimal (distribution-spec-only) image or a full image including extensions.

Enabling metrics for a full zot image with extensions

Add the metrics attribute under extensions in the configuration file to enable and configure metrics, as shown in the following example.

"extensions": {
+    "metrics": {
+        "enable": true,
+        "prometheus": {
+            "path": "/metrics"
+        }
+    }
+}
+

The following table lists the configurable attributes for metrics collection.

Attribute Description
enable If this attribute is missing, metrics collection is enabled by default. Metrics collection can be disabled by setting this attribute to false.
prometheus Attributes under prometheus contain configuration settings for the Prometheus node exporter.
path The server path on which metrics will be exposed.

Collecting metrics from a minimal zot image using a node exporter

Although a minimal zot image does not contain a node exporter, it exposes internal metrics in a Prometheus format for collection by a separate node exporter tool such as zxp. The zot companion binary zxp is a node exporter that can be deployed with a minimal zot image in order to scrape metrics from the zot server.

Metrics are automatically enabled in the zot server upon first scrape from the node exporter and the metrics are automatically disabled when the node exporter has not performed any scraping for some period. No extra zot configuration is needed for this behavior.

You can download the zxp executable binary for your server platform and architecture under "Assets" on the GitHub zot releases page.

The binary image is named using the target platform and architecture. For example, the binary for an Intel-based MacOS server is zxp-darwin-amd64. To configure the zxp example image, run this command:

zxp-darwin-amd64 config zxp-config-file

💡 For convenience, you can rename the binary image file to simply zxp.

💡 A sample Dockerfile for zxp is available at Dockerfile-zxp.

The configuration file of zxp contains connection details for the zot server from which it will scrape metrics. The following JSON structure is an example of the zxp-config-file contents:

{
+    "Server": {
+        "protocol": "http",
+        "host": "127.0.0.1",
+        "port": "8080"
+    },
+    "Exporter": {
+        "port": "8081",
+        "log": {
+            "level": "debug"
+        }
+    }
+}
+

💡 The zxp module does not have Prometheus integration.

The zxp module is not needed with a full zot image.


Last update: September 13, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/pprofiling/index.html b/v2.0.2/articles/pprofiling/index.html new file mode 100644 index 0000000..8528af5 --- /dev/null +++ b/v2.0.2/articles/pprofiling/index.html @@ -0,0 +1,32 @@ + Performance Profiling - zotregistry.dev
Skip to content

Performance Profiling in zot

👉 Use zot's built-in profiling tools to collect and analyze runtime performance.

The profiling capabilities within zot allow a zot administrator to collect and export a range of diagnostic performance data such as CPU intensive function calls, memory allocations, and execution traces. The collected data can then be analyzed using Go tools and a variety of available visualization tools.

✏ If authentication is enabled, only a zot admin user can access the APIs for profiling.

✏ All examples in this article assume that the zot registry is running at localhost:8080.

What data is available?

The zot source code incorporates golang's pprof package of runtime analysis tools to collect data for the following performance-related profiles:

Profile Description
allocs A sampling of all past memory allocations.
block Stack traces that led to blocking on synchronization primitives.
cmdline The command line invocation of the current program.
goroutine Stack traces of all current goroutines. Use debug=2 as a URL query parameter to export in the same format as an unrecovered panic.
heap A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.
mutex Stack traces of holders of contended mutexes.
profile CPU usage profile. You can specify the duration in the seconds URL query parameter. After receiving the profile file, use the go tool pprof command to investigate the profile.
threadcreate Stack traces that led to the creation of new OS threads.
trace A trace of execution of the current program. You can specify the duration in the seconds URL query parameter. After you get the trace file, use the go tool trace command to investigate the trace.

To return a current HTML-format profile list along with a count of currently available records for each profile, use the following API command:

/v2/_zot/pprof/
+

✏ If authentication is enabled, only an admin user can access this API.

How do I export profile data?

To collect and export any available profile, use the following API command format:

/v2/_zot/pprof/<profile-type>[?<query-parameters>]
+

The following example shows an API request for the CPU usage profile named profile using a collection window of 30 seconds:

$ curl -s http://localhost:8080/v2/_zot/pprof/profile?seconds=30 > cpu.prof
+

This command example creates an output data file named "cpu.prof".

  • The query parameter ?seconds=<number> specifies the number of seconds to gather the profile data. If this parameter is not specified, the default is 30 seconds.
  • In this example, the raw output data is redirected to a file named "cpu.prof". Alternatively, you can use curl -O to create a file with the default profile name (in this case, "profile"). If no output file is specified by either a cURL flag or an output redirection, the cURL command fails with "Failure writing output to destination".
  • The command output file is in a machine-readable format that can be interpreted by performance analyzers.

Analyzing the CPU usage profile using go tool pprof

Go's pprof package provides a variety of presentation formats for analyzing runtime performance.

For detailed information, see the pprof documentation.

Generating a pprof web presentation

When an HTTP port is specified as a command flag, the go tool pprof command installs and opens a local web server that provides a web interface for viewing and analyzing the profile data. This example opens a localhost page at port 9090 for viewing the CPU usage data captured in the profile file named "cpu.prof".

$ go tool pprof -http=:9090 cpu.prof
+Serving web UI on http://localhost:9090
+

The pprof web view offers several options for viewing and interpreting the collected performance data. Select VIEW to see the available options:

pprof-view.jpg

A Flame Graph can be very useful for analyzing CPU usage:

profiling-flame.svg

Generating a graphic image

The pprof package can generate graphic representations of profile data in many formats. This example generates a PNG file representing the CPU usage in the "cpu.prof" file.

$ go tool pprof -png cpu.prof
+Generating report in profile001.png
+

profile001.png

Opening a pprof interactive session

This example opens an interactive session with pprof and executes the pprof top command, which displays the top ten modules by CPU usage during the profiling capture window.

$ go tool pprof cpu.prof
+Type: cpu
+Time: Sep 26, 2023 at 10:01am (PDT)
+Duration: 30s, Total samples = 10ms (  0.1%)
+Entering interactive mode (type "help" for commands, "o" for options)
+(pprof) top
+Showing nodes accounting for 10ms, 100% of 10ms total
+    flat  flat%   sum%        cum   cum%
+    10ms   100%   100%       10ms   100%  runtime.pthread_cond_signal
+        0     0%   100%       10ms   100%  runtime.findRunnable
+        0     0%   100%       10ms   100%  runtime.mcall
+        0     0%   100%       10ms   100%  runtime.notewakeup
+        0     0%   100%       10ms   100%  runtime.park_m
+        0     0%   100%       10ms   100%  runtime.runSafePointFn
+        0     0%   100%       10ms   100%  runtime.schedule
+        0     0%   100%       10ms   100%  runtime.semawakeup
+(pprof)
+

Analyzing the trace profile using go tool trace

You can collect trace data with the trace profile, as in this example:

  $ curl -s -v http://localhost:8080/v2/_zot/pprof/trace?seconds=30 > trace.prof
+

Using the go tool trace package, you can analyze the trace data captured in the "trace.prof" example file:

$ go tool trace trace.prof
+2023/09/21 16:58:58 Parsing trace...
+2023/09/21 16:58:58 Splitting trace...
+2023/09/21 16:58:58 Opening browser. Trace viewer is listening on http://127.0.0.1:62606
+

The go tool trace command installs and opens a local web server that provides a web interface for viewing and analyzing the trace data.

As an alternative, you can generate a pprof-like profile from the trace file using the following command:

$ go tool trace -pprof=[net|sync|syscall|sched] <filename>
+

For example:

$ go tool trace -pprof=net trace.prof
+

Last update: October 12, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/retention/index.html b/v2.0.2/articles/retention/index.html new file mode 100644 index 0000000..99d52a3 --- /dev/null +++ b/v2.0.2/articles/retention/index.html @@ -0,0 +1,99 @@ + Retention Policies - zotregistry.dev
Skip to content

Configuring zot Tag Retention Policies

👉 To optimize image storage, you can configure tag retention policies to remove images that are no longer needed.

Tag retention policies in zot can specify how many tags of a given repository to retain or how long to retain certain tags.

You can define tag retention policies that apply one or more of the following rules:

  • Top <n> tags most recently pushed
  • Top <n> tags most recently pulled
  • Tags pushed in the past <n> hours
  • Tags pulled in the past <n> hours
  • Tags matching a regular expression (regex) pattern

Configuring retention policies

Retention policies are configured in the storage section of the zot configuration file under the retention attribute. One or more policies can be grouped under the policies attribute.

By default, if no retention policies are defined, all tags are retained.

⚠ If at least one keepTags policy is defined for a repository, all tags not matching those policies are removed. To avoid unintended removals, we recommend defining a default policy, as described in Configuration notes.

Configuration example

The following example is a simple retention configuration with two policies:

  • The first includes all available configuration attributes.
  • The second acts as a default policy.

simple policy example

  "storage": {
+    "retention": {
+      "dryRun": false,
+      "delay": "24h",
+      "policies": [
+        {
+          "repoNames": ["infra/*", "tmp/**"],
+          "deleteReferrers": false,
+          "deleteUntagged": true,
+          "KeepTags": [{
+            "patterns": ["v2.*", ".*-prod"],
+            "mostRecentlyPushedCount": 10,
+            "mostRecentlyPulledCount": 10,
+            "pulledWithin": "720h",
+            "pushedWithin": "720h"
+          }]  
+        },
+        {
+          "keepTags": [{
+            "patterns": [".*"]
+          }]
+        }
+      ]
+    }
+  }
+

Configurable attributes

The following table lists the attributes available in the retention policy configuration.

Attribute Value Description
dryRun boolean If true, will log a removal action without actually removing the image. Default is false.
delay time Remove untagged and referrers only if they are older than the specified <time> hours, such as 24h.
policies list A list of policies.
repositories list A list of glob patterns to match repositories.
deleteReferrers boolean If true, delete manifests with a missing Subject. Default is false.
deleteUntagged boolean If true, delete untagged manifests. Default is true.
keepTags list Criteria for tags to retain always.
mostRecentlyPushedCount count Retains the top <count> most recently pushed tags.
mostRecentlyPulledCount count Retains the top <count> most recently pulled tags.
pushedWithin time Retains the tags pushed during the last <time> hours, such as 24h.
pulledWithin time Retains the tags pulled during the last <time> hours, such as 24h.
patterns regex See Notes.

Configuration notes

  • A repository will apply the first policy it matches.
  • If a repository matches no policy, the repository and all its tags are retained.
  • If at least one keepTags policy is defined for a repository, all tags not matching those policies are removed.
  • If keepTags is present but empty, all tags are retained.
  • When multiple rules are configured, a tag is retained if it meets at least one rule.
  • When you specify a regex pattern combined with one or more rules, the rules are applied only to those tags matching the regex.
  • When you specify a regex pattern with no rules other than the default, all tags matching the pattern are retained.
  • In the repositories list, a single asterisk (/*) matches all first-level items in the repository. A double asterisk (/**) matches all recursively.

⚠ We recommend defining a default keepTags policy, such as the following example, as the last policy in the policy list. All tags that don't match the preceding policies will be retained by this default policy:

default policy example

  {
+    "keepTags": [{                               
+        "patterns": [".*"]
+      }]
+  }
+

Complete configuration file example

The following example shows the configuration of multiple retention policies in the context of a complete configuration file.

{
+  "distSpecVersion": "1.1.0-dev",
+  "storage": {
+    "rootDirectory": "/tmp/zot",
+    "gc": true,
+    "gcDelay": "2h",
+    "gcInterval": "1h",
+    "retention": {
+      "dryRun": false,
+      "delay": "24h",
+      "policies": [
+        {
+          "repositories": ["infra/*", "prod/*"],
+          "deleteReferrers": false,
+          "keepTags": [{
+            "patterns": ["v2.*", ".*-prod"]
+          },
+          {
+            "patterns": ["v3.*", ".*-prod"],
+            "pulledWithin": "168h"
+          }]
+        },
+        {
+          "repositories": ["tmp/**"],
+          "deleteReferrers": true,
+          "deleteUntagged": true,
+          "keepTags": [{
+            "patterns": ["v1.*"],
+            "pulledWithin": "168h",
+            "pushedWithin": "168h"
+          }]
+        },
+        {
+          "repositories": ["**"],
+          "deleteReferrers": true,
+          "deleteUntagged": true,
+          "keepTags": [{
+            "mostRecentlyPushedCount": 10,
+            "mostRecentlyPulledCount": 10,
+            "pulledWithin": "720h",
+            "pushedWithin": "720h"
+          }]
+        }
+      ]
+    },
+    "subPaths": {
+      "/a": {
+        "rootDirectory": "/tmp/zot1",
+        "dedupe": true,
+        "retention": {
+          "policies": [
+            {
+              "repositories": ["infra/*", "prod/*"],
+              "deleteReferrers": false
+            }
+          ]
+        }
+      }
+    }
+  },
+  "http": {
+    "address": "127.0.0.1",
+    "port": "8080"
+  },
+  "log": {
+    "level": "debug"
+  }
+}
+

Last update: November 1, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/security-posture/index.html b/v2.0.2/articles/security-posture/index.html new file mode 100644 index 0000000..a6f6404 --- /dev/null +++ b/v2.0.2/articles/security-posture/index.html @@ -0,0 +1 @@ + Security Posture - zotregistry.dev
Skip to content

zot Security Posture

👉 An overview of zot build-time and runtime security hardening features, including:

  • Build-time hardening such as PIE-mode builds
  • Minimal-build option for smaller attack surface
  • Open Source Security Foundation best practices for CI/CD
  • Non-root deployment
  • Robust authentication/authorization options

The zot project takes a defense-in-depth approach to security, applying industry-standard best practices at various stages. Recognizing that security hardening and product features are sometimes in conflict with each other, we also provide flexibility both at build and deployment time.

Build-time hardening

The following are the steps taken during build-time.

PIE build-mode

The zot binary is built with PIE build-mode enabled to take advantage of ASLR support in modern operating systems such as Linux ASLR. While zot is intended to be a long-running service (without frequent restarts), it prevents attackers from developing a generic attack that depends on predictable memory addresses across multiple zot deployments.

Conditional builds

Functionality in zot is broadly organized as a core Distribution Specification implementation and additional features as extensions. The rationale behind this approach is to minimize or control library dependencies that get included in the binary and consequently the attack surface.

We currently build and release two image flavors:

  • minimal, which is a minimal Distribution Specification conformant registry, and

  • full, which incorporates the minimal build and all extensions

The minimal flavor is for the security-minded and minimizes the number of dependencies and libraries. The full flavor is for the functionality-minded with the caveat that the attack surface of the binary is potentially broader. However by no means are these the only options. Our build (via the Makefile) provides the flexibility to pick and choose extensions in order to build a binary between minimal and full. For example,

make EXTENSIONS=search binary

produces a zot binary with only the search feature enabled.

CI/CD pipeline

zot CI/CD process attempts to align with the Open Source Security Foundation (OSSF) best practices guidelines to achieve high code quality.

Code reviews

zot is an open source project and all code submissions are open and transparent. Every pull request (PR) submitted to the project repository must be reviewed by the code owners. We have additional CI/CD workflows monitoring for unreviewed commits.

CI/CD checks

All PRs must pass the full CI/CD pipeline checks including unit, functional, and integration tests, code quality and style checks, and performance regressions. In addition, all binaries produced are subjected to further security scans to detect any known vulnerabilities.

Runtime hardening

The following steps can be taken to harden a zot deployment.

Unprivileged runtime process

Running zot doesn’t require root privileges. In fact, the recommended approach is to create a separate user/group ID for the zot process.

Authentication

All interactions with zot are over HTTP APIs, and htpasswd-based local authentication, LDAP, mutual TLS, and token-based authentication mechanisms are supported. We strongly recommend enabling a suitable mechanism for your deployment use case in order to prevent unauthorized access. See the provided authentication examples.

Access control

Following authentication, it is further possible to allow or deny actions by a user on a particular repository stored on the zot registry. See the provided access control examples.

Vulnerability scans

Apart from hardening the deployment itself, zot also supports security scanning of stored container images.

Reporting security issues

We understand that no software is perfect and in spite of our best efforts, security bugs may be found. Refer to our security policy for taking a responsible course of action when reporting security bugs.


Last update: December 21, 2022
\ No newline at end of file diff --git a/v2.0.2/articles/storage/index.html b/v2.0.2/articles/storage/index.html new file mode 100644 index 0000000..3760231 --- /dev/null +++ b/v2.0.2/articles/storage/index.html @@ -0,0 +1,165 @@ + Storage Planning - zotregistry.dev
Skip to content

Storage Planning with zot

👉 zot supports the following features to provide OCI standards-based, vendor-agnostic image storage:

  • Local and remote file storage
  • Inline deduplication and garbage collection
  • Data scrubbing in background

Storage model

Data handling in zot revolves around two main principles: that data and APIs on the wire conform to the OCI Distribution Specification and that data on the disk conforms to the OCI Image Layout Specification. As a result, any client that is compliant with the Distribution Specification can read from or write to a zot registry. Furthermore, the actual storage is simply an OCI Image Layout. With only these two specification documents in hand, the entire data flow inside can be easily understood.

✏ zot does not implement, support, or require any vendor-specific protocols, including that of Docker.

Hosting an OCI image layout

Because zot supports the OCI image layout, it can readily host and serve any directories holding a valid OCI image layout even when those directories have been created elsewhere. This property of zot is suitable for use cases in which container images are independently built, stored, and transferred, but later need to be served over the network.

Storage features

Exposing flexibility in storage capabilities is a key tenet for catering to the requirements of varied environments ranging from cloud to on-premises to IoT.

Commit

Most modern filesystems buffer and flush RAM data to disk after a delay. The purpose of this function is to improve performance at the cost of higher disk memory usage. In embedded devices such as Raspberry Pi, for example, where RAM may be very limited and at a premium, it is desirable to flush data to disk more frequently. The zot storage configuration exposes an option called commit which, when enabled, causes data writes to be committed to disk immediately. This option is disabled by default.

Deduplication

Deduplication is a storage space saving feature wherein only a single copy of specific content is maintained on disk while many different image manifests may hold references to that same content. The deduplication option (dedupe) is also available for supported cloud storage backends.

Upon startup, zot enforces the dedupe status on the existing storage. If the dedupe status upon startup is true, zot deduplicates all blobs found in storage, both local and remote. If the status upon startup is false, zot restores cloud storage blobs to their original state. There is no need for zot to restore local filesystem storage if hard links are used.

Garbage collection

After an image is deleted by deleting an image manifest, the corresponding blobs can be purged to free up space. However, since Distribution Specification APIs are not transactional between blob and manifest lifecycle, care must be taken so as not to put the storage in an inconsistent state. Garbage collection in zot is an inline feature meaning that it is not necessary to take the registry offline. See Configuring garbage collection for details.

Scrub

The scrub function, available as an extension, makes it possible to ascertain data validity by computing hashes on blobs periodically and continuously so that any bit rot is caught and reported early.

Storage backends

The following types of storage backends are supported.

Local filesystem

zot can store and serve files from one or more local directories. A minimum of one root directory is required for local hosting, but additional hosted directories can be added. When accessed by HTTP APIs, all directories can appear as a single data store.

✏ Remote filesystems that are mounted and accessible locally such as NFS or fuse are treated as local filesystems.

Remote filesystem

zot can also store data remotely in the cloud, using the storage APIs of the cloud service. Currently, zot supports only the AWS s3 storage service.

Example: configuration for remote (s3) storage

Click here to view a sample zot configuration for remote storage.
{
+    "distSpecVersion": "1.0.1-dev",
+    "storage": {
+        "rootDirectory": "/tmp/zot",
+        "dedupe": true,
+        "storageDriver": {
+            "name": "s3",
+            "rootdirectory": "/zot",
+            "region": "us-east-2",
+            "bucket": "zot-storage",
+            "secure": true,
+            "skipverify": false
+        },
+        "cacheDriver": {
+            "name": "dynamodb",
+            "endpoint": "http://localhost:4566",
+            "region": "us-east-2",
+            "tableName": "MainTable"
+        },
+    },
+    "http": {
+        "address": "127.0.0.1",
+        "port": "8080"
+    },
+    "log": {
+        "level": "debug"
+    }
+}
+

Configuring zot storage

Filesystem storage is configured with the storage attribute in the zot configuration file, as shown in the following example.

    "storage":{
+        "rootDirectory":"/tmp/zot",
+        "commit": true,
+        "dedupe": true,
+        "gc": true,
+        "gcDelay": "1h",
+        "gcInterval": "24h"
+    }
+

Configurable attributes

The following table lists the attributes of the storage configuration.

Attribute Description

rootDirectory

Location of the images stored in the server file system.

commit

For faster performance, data written by zot is retained in memory before being periodically committed to disk by the operating system. To eliminate this retention time and cause data to be written to disk immediately, set to true. This prevents data loss but reduces performance.

dedupe

If the server filesystem supports hard links, you can optimize storage space by enabling inline deduplication of layers and blobs that are shared among multiple container images. Deduplication is enabled by default. Set to false to disable deduplication.

gc

When an image is deleted, either by tag or by reference, orphaned blobs can lead to wasted storage. Garbage collection (gc) is enabled by default to reclaim this space. Set to false to disable garbage collection.

gcDelay

(Optional) If garbage collection is enabled, causes it to run once after the specified delay time. The default is 1 hour. Requires the gc attribute to be true.

gcInterval

(Optional) If garbage collection is enabled, causes periodic collection at the specified interval. Must be set based on use cases and user workloads. If no value is specified, there is no periodic collection. Requires the gc attribute to be true.

subpaths

You can store and serve images from multiple filesystems, each with their own repository paths and settings. The following example shows three subpaths.

"storage":{
+  "subPaths": {
+    "/a": {
+      "rootDirectory": "/tmp/zot1",
+      "dedupe": true,
+      "gc": true
+    },
+    "/b": {
+      "rootDirectory": "/tmp/zot2",
+      "dedupe": true
+    },
+    "/c": {
+      "rootDirectory": "/tmp/zot3",
+      "dedupe": false
+    }
+  }
+}

storageDriver

(Remote storage only) Contains settings for a remote storage service. See Configuring remote storage with s3 for details.

cacheDriver

Specifies which database is used to store duplicate blobs when deduplication is enabled. See Cache drivers for details.

Configuring garbage collection

The zot configuration model allows for enabling and disabling garbage collection (gc) and specifying a periodic interval (gcInterval) for collection.

gc gcInterval Result
false n/a GC disabled
omitted n/a GC enabled with 1 hour interval (default)
true omitted GC enabled with 1 hour interval
true 0 GC runs only once
true >0 GC enabled with specified interval

The configuration model also allows the configuration of a tunable delay (gcDelay), which can be set depending on client network speeds and the size of blobs. The gcDelay attribute causes collection to run once after the specified delay time. This attribute has a default value of one hour (1h).

Configuring remote storage with s3

To configure an Amazon Simple Storage Service (s3) bucket for zot, use the storageDriver attribute in the zot configuration file, as shown in the following example:

    "storage": {
+        "rootDirectory": "/tmp/zot",
+        "storageDriver": {
+            "name": "s3",
+            "region": "us-east-2",
+            "bucket": "zot-storage",
+            "secure": true,
+            "skipverify": false,
+            "accesskey": "<YOUR_ACCESS_KEY_ID>",
+            "secretkey": "<YOUR_SECRET_ACCESS_KEY>"
+        }
+    }
+

For descriptions of the configurable attributes for storageDriver, see the s3 storage driver project in GitHub.

s3 Credentials

In the s3 configuration file example, the s3 credentials were configured with the attributes accesskey and secretkey. As an alternative, you can omit these attributes from the configuration file and you can configure them using environment variables or a credential file.

  • Environment variables

    zot looks for credentials in the following environment variables:

    AWS_ACCESS_KEY_ID
    +AWS_SECRET_ACCESS_KEY
    +AWS_SESSION_TOKEN (optional)
    +
  • Credential file

    A credential file is a plaintext file that contains your access keys, as shown in the following example.

    [default]
    +aws_access_key_id = <YOUR_DEFAULT_ACCESS_KEY_ID>
    +aws_secret_access_key = <YOUR_DEFAULT_SECRET_ACCESS_KEY>
    +
    +[test-account]
    +aws_access_key_id = <YOUR_TEST_ACCESS_KEY_ID>
    +aws_secret_access_key = <YOUR_TEST_SECRET_ACCESS_KEY>
    +
    +[prod-account]
    +; work profile
    +aws_access_key_id = <YOUR_PROD_ACCESS_KEY_ID>
    +aws_secret_access_key = <YOUR_PROD_SECRET_ACCESS_KEY>
    +

    The [default] heading defines credentials for the default profile, which zot will use unless you configure it to use another profile. You can specify a profile using the AWS_PROFILE environment variable as in this example:

    AWS_PROFILE=test-account
    +

    The credential file must be named credentials. The file must be located in the .aws/ subdirectory in the home directory of the same server that is running your zot application.

For more details about specifying s3 credentials, see the AWS documentation.

S3 permissions scopes

The following AWS policy is required by zot for push and pull.

✏ Replace S3_BUCKET_NAME with the name of your s3 bucket.

[AWS CONFIGURATION]
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "s3:ListBucket",
+        "s3:GetBucketLocation",
+        "s3:ListBucketMultipartUploads"
+      ],
+      "Resource": "arn:aws:s3:::<S3_BUCKET_NAME>"
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "s3:PutObject",
+        "s3:GetObject",
+        "s3:DeleteObject",
+        "s3:ListMultipartUploadParts",
+        "s3:AbortMultipartUpload"
+      ],
+      "Resource": "arn:aws:s3:::<S3_BUCKET_NAME>/*"
+    }
+  ]
+}
+

For more details about configuring AWS policies, see the AWS documentation.

Cache drivers

A cache driver is used to store duplicate blobs when dedupe is enabled. zot supports database caching using BoltDB as the cache driver for local filesystems and DynamoDB for remote filesystems.

BoltDB

If you don't specify a cache driver, zot defaults to BoltDB. BoltDB is stored either in zot's root directory or in the subpath root directory.

    "storage": {
+        "rootDirectory": "/tmp/zot",
+        "dedupe": true
+    }
+

In this example, BoltDB can be found at /tmp/zot/cache.db.

DynamoDB

To use DynamoDB as the cache driver, the following storage configuration must be present:

  • dedupe is enabled
  • remoteCache is enabled
  • cacheDriver attribute is configured as in the following example:
    "storage": {
+        "rootDirectory": "/tmp/zot",
+        "dedupe": true,
+        "remoteCache": true,
+        "cacheDriver": {
+            "name": "dynamodb",                  // driver name
+            "endpoint": "http://localhost:4566", // aws endpoint
+            "region": "us-east-2"                // aws region
+            "cacheTablename": "ZotBlobTable"     // table to store deduped blobs
+        }
+    },
+

The AWS GO SDK loads additional configuration and credentials values from your environment variables, shared credentials, and shared configuration files.

If the search extension is enabled, additional parameters are required:

        "cacheDriver": {
+            "name": "dynamodb",
+            "endpoint": "http://localhost:4566",
+            "region": "us-east-2",
+            "cacheTablename": "ZotBlobTable",
+            // used by search extensions
+            "repoMetaTablename": "ZotRepoMetadataTable",
+            "manifestDataTablename": "ZotManifestDataTable",
+            "versionTablename": "ZotVersion"
+        }
+

DynamoDB permission scopes

The following AWS policy is required by zot for caching blobs.

✏ Replace DYNAMODB_TABLE with the name of your table, which should be the value of cacheTablename in the zot configuration.

In this case, the AWS Resource value would be arn:aws:dynamodb:*:*:table/ZotBlobTable

[AWS CONFIGURATION]
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "dynamodb:CreateTable",
+        "dynamodb:GetItem",
+        "dynamodb:UpdateItem",
+        "dynamodb:DeleteItem"
+      ],
+      "Resource": "arn:aws:dynamodb:*:*:table/<DYNAMODB_TABLE>"
+    }
+  ]
+}
+

For more details about configuring AWS DynamoDB, see the AWS documentation.

Remote storage subpaths

As in the case with local filesystem storage, you can use multiple remote storage locations using the subpath attribute, as in the following example.

"subPaths": {
+    "/a": {
+        "rootDirectory": "/zot-a",
+        "storageDriver": {
+            "name": "s3",
+            "region": "us-east-2",
+            "bucket": "zot-storage",
+            "secure": true,
+            "skipverify": false
+        }
+    },
+    "/b": {
+       .
+       .
+       .
+    }
+}
+

The subPaths feature ties together several separate storage filesystems and backends behind the same HTTP API interface. In the example above, both repository paths "/a" and "/b" are exposed to clients. Content on these two paths can be hosted completely separately by different storage services, locations, or filesystems, with no difference to the user interface and no perceptible difference to the user experience. This is useful if one wants to serve existing OCI images from different backends or if storage can be expanded only by using different backing stores.

💡 zot also supports different storage drivers for each subpath.


Last update: September 13, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/verifying-signatures/index.html b/v2.0.2/articles/verifying-signatures/index.html new file mode 100644 index 0000000..4ae19d2 --- /dev/null +++ b/v2.0.2/articles/verifying-signatures/index.html @@ -0,0 +1,86 @@ + Verifying Image Signatures - zotregistry.dev
Skip to content

Verifying image signatures

Images stored in zot can be signed with a digital signature to verify the source and integrity of the image. The digital signature can be verified by zot using public keys or certificates uploaded by the user.

To verify image signatures, zot supports the following tools:

Enabling image signature verification

To enable image signature verification, add the trust attribute under extensions in the zot configuration file and enable one or more verification tools, as shown in the following example:

"extensions": {
+  "trust": {
+    "enable": true,
+    "cosign": true,
+    "notation": true
+  }
+}
+

The following table lists the configurable attributes of the trust extension.

Attribute Description
enable If this attribute is missing, signature verification is disabled by default. Signature verification is enabled by including this attribute and setting it to true. You must also enable at least one of the verification tools.
cosign Set to true to enable signature verification using the cosign tool.
notation Set to true to enable signature verification using the notation tool.

What is needed for verifying signatures

To verify the validity of a signature for an image, zot makes use of two types of files:

  • A public key file that pairs with the private key used to sign an image with cosign

  • A certificate file that is used to sign an image with notation

Upload these files using an extension of the zot API, as shown in the following examples:

  • To upload a public key for cosign:

    API path

    /v2/_zot/ext/cosign"
    +
    Example request
    curl --data-binary @file.pub -X POST "http://localhost:8080/v2/_zot/ext/cosign"
    +
    Result

    The uploaded file is stored in the _cosign directory under the rootDir specified in the zot configuration file or in the Secrets Manager.

  • To upload a certificate for notation:

    API path

    /v2/_zot/ext/notation?truststoreType=ca
    +

    When uploading a certificate, you should specify the truststoreType. If the truststore is a certificate authority, the value is ca. This is the default if this attribute is omitted.

    Example request

    curl --data-binary @certificate.crt -X POST "http://localhost:8080/v2/_zot/ext/notation?truststoreType=ca"
    +
    Result

    The uploaded file is stored in the _notation/truststore/x509/{truststoreType}/default directory under the rootDir specified in the zot configuration file or in the Secrets Manager.

Where needed files are stored

Uploaded public keys and certificates are stored in the local filesystem, in specific directories named _cosign and _notation under $rootDir, or in the Secrets Manager.

  • The _cosign directory contains uploaded public key files in the following structure:

    _cosign
    +├── $publicKey1
    +└── $publicKey2
    +
  • The _notation directory contains a set of files in the following structure:

    _notation
    +├── trustpolicy.json
    +└── truststore
    +    └── x509
    +        └── $truststoreType
    +            └── default
    +                └── $certificate
    +

    In this directory, the trustpolicy.json file contains content that is updated automatically whenever a new certificate is added to a new truststore. This content cannot be changed by the user. An example of the trustpolicy.json file content is shown below:

    {
    + "version": "1.0",
    +  "trustPolicies": [
    +    {
    +      "name": "default-config",
    +      "registryScopes": [ "*" ],
    +      "signatureVerification": {
    +        "level" : "strict" 
    +      },
    +      "trustStores": ["ca:default","signingAuthority:default"],
    +      "trustedIdentities": [
    +        "*"
    +      ]
    +    }
    +  ]
    +}
    +
    • By default, the trustpolicy.json file sets the signatureVerification.level property to strict, which enforces all validations. For example, a signature is not trusted if its certificate has expired, even if the certificate verifies the signature.

    • The trustpolicy.json file contains two default truststores, ca:default and signingAuthority:default. This list of truststores is not updated when a new certificate is uploaded.

    • The content of the trustStores field will match the content of the _notation/truststore directory.

How signature verification works

Based on the uploaded files and the information about images stored in zot's database, signature verification is performed for all signed images. The verification result for each signed image is stored in the database and is visible from GraphQL. The stored information about a signature includes:

  • The tool that was used to generate the signature, such as cosign or notation
  • The trustworthiness of the signature, such as whether a certificate or public key exists that can successfully verify the signature
  • The author of the signature, which can be either:

    • The public key, for signatures generated using cosign
    • The subject of the certificate, for signatures generated using notation

Example of GraphQL output

Sample request

{
+  Image(image: "busybox:latest") {
+    Digest
+    IsSigned
+    Tag
+    SignatureInfo {
+        Tool
+        IsTrusted
+        Author
+    }
+  }
+}
+

Sample response

{
+  "data": {
+    "Image": {
+      "Digest":"sha256:6c19fba547b87bde9a45df2f8563e0c61826d098dd30192a2c8b86da1e1a6360",
+      "IsSigned": true,
+      "Tag": "latest",
+      "SignatureInfo":[
+        {
+          "Tool":"cosign",
+          "IsTrusted":false,
+          "Author":""
+        },
+        {
+          "Tool":"cosign",
+          "IsTrusted":false,
+          "Author":""
+        },
+        {
+          "Tool":"cosign",
+          "IsTrusted": true,
+          "Author":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9pN+/hGcFlh4YYaNvZxNvuh8Qyhl\npURz77qScOHe3DqdmiWiuqIseyhEdjEDwpL6fHRwu3a2Nd9wbKqm0la76w==\n-----END PUBLIC KEY-----\n"
+        },
+        {
+          "Tool":"notation",
+          "IsTrusted": false,
+          "Author":"CN=v4-test,O=Notary,L=Seattle,ST=WA,C=US"
+        },
+        {
+          "Tool":"notation",
+          "IsTrusted": true,
+          "Author":"CN=multipleSig,O=Notary,L=Seattle,ST=WA,C=US"
+        }
+      ]
+    }
+  }
+}
+

Last update: September 13, 2023
\ No newline at end of file diff --git a/v2.0.2/articles/workflow/index.html b/v2.0.2/articles/workflow/index.html new file mode 100644 index 0000000..3109c6c --- /dev/null +++ b/v2.0.2/articles/workflow/index.html @@ -0,0 +1,207 @@ + Software Provenance Workflow Using OCI Artifacts - zotregistry.dev
Skip to content

Software Provenance Workflow Using OCI Artifacts

👉 This article demonstrates an end-to-end workflow for installing a zot registry, then pushing and signing an image and a related artifact, such as an SBOM.

Workflow

The following sections describe the step-by-step workflow. To view the steps combined into a single script, see Reference: Full workflow script.

For the workflow examples, the zot registry is assumed to be installed and running at localhost:8080.

Step 1: Download the client tools

This workflow uses the regctl registry client and the cosign image signing tool. As a first step, we download binaries for these tools in a tools directory.

TEST_TMPDIR=$(mktemp -d "${PWD}/artifact-test-${1:+-$1}.XXXXXX")
+
+TOOLSDIR=$(pwd)/hack/tools
+mkdir -p ${TOOLSDIR}/bin
+
+REGCLIENT=${TOOLSDIR}/bin/regctl
+REGCLIENT_VERSION=v0.5.1
+curl -Lo ${REGCLIENT} https://github.com/regclient/regclient/releases/download/${REGCLIENT_VERSION}/regctl-linux-amd64
+chmod +x ${REGCLIENT}
+
+COSIGN=${TOOLSDIR}/bin/cosign
+COSIGN_VERSION=2.1.1
+curl -Lo ${COSIGN} https://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}/cosign-linux-amd64 
+chmod +x ${COSIGN}
+

Step 2: Deploy an OCI registry with referrers support (zot)

Next, we execute the following tasks to deploy an OCI registry:

  • Copy a zot executable binary to the server.
  • Create a basic configuration file for the zot server, specifying the local root directory, the network location, and the port number.
  • Launch zot with the newly-created configuration file.
  • Looping with a periodic cURL query, detect when zot is up and running.
ZOT=${TOOLSDIR}/bin/zot
+ZOT_VERSION=2.0.0-rc6
+curl -Lo ${ZOT} https://github.com/project-zot/zot/releases/download/v${ZOT_VERSION}/zot-linux-amd64-minimal
+chmod +x ${ZOT}
+
+ZOT_HOST=localhost
+ZOT_PORT=8080
+
+# function to start zot and test for readiness
+function zot_setup() {
+cat > $TEST_TMPDIR/zot-config.json << EOF
+{
+  "distSpecVersion": "1.1.0-dev",
+  "storage": {
+      "rootDirectory": "$TEST_TMPDIR/zot"
+  },
+  "http": {
+      "address": "$ZOT_HOST",
+      "port": "$ZOT_PORT"
+  },
+  "log": {
+      "level": "error"
+  }
+}
+EOF
+  # start zot as a background task
+  ${ZOT} serve $TEST_TMPDIR/zot-config.json &
+  pid=$!
+        # wait until service is up
+  count=5
+  up=0
+  while [[ $count -gt 0 ]]; do
+    if [ ! -d /proc/$pid ]; then
+      echo "zot failed to start or died"
+      exit 1
+    fi
+    up=1
+    curl -f http://$ZOT_HOST:$ZOT_PORT/v2/ || up=0
+    if [ $up -eq 1 ]; then break; fi
+    sleep 1
+    count=$((count - 1))
+  done
+  if [ $up -eq 0 ]; then
+    echo "Timed out waiting for zot"
+    exit 1
+  fi
+  # setup an OCI client
+  ${REGCLIENT} registry set --tls=disabled $ZOT_HOST:$ZOT_PORT
+}
+
+# call the function to start zot
+zot_setup
+

Step 3: Copy an image to the OCI registry

This step copies a busybox container image into the registry.

skopeo copy --format=oci --dest-tls-verify=false docker://busybox:latest docker://${ZOT_HOST}:${ZOT_PORT}/busybox:latest
+

This step creates a simple artifact file and associates it with the busybox image in the registry.

cat > ${TEST_TMPDIR}/artifact.yaml << EOF
+key:
+  val: artifact
+EOF
+${REGCLIENT} artifact put --artifact-type application/yaml -f ${TEST_TMPDIR}/artifact.yaml --subject ${ZOT_HOST}:${ZOT_PORT}/busybox:latest
+

The --subject command flag associates the artifact file with the specified subject (in this case, the busybox image). If no subject is specified by the command, the artifact is considered independent and not associated with any existing image.

Step 5: Display the artifact tree

This step prints the artifact tree of the busybox image. The tree includes the artifact yaml file, showing the association of the artifact to the busybox image.

These script commands define REF0 as the artifact that was uploaded referring to the first container image.

REF0=$(${REGCLIENT} artifact tree --format '{{jsonPretty .}}' localhost:8080/busybox:latest | jq .referrer[0].reference.Digest)
+REF0="${REF0:1:-1}"
+

The following example shows the command and its output:

$ regctl artifact tree localhost:8080/busybox:latest
+
+Ref: localhost:8080/busybox:latest  
+Digest: sha256:9172c5f692f2c65e4f773448503b21dba2de6454bd159905c4bf6d83176e4ea3
+Referrers:  
+   - sha256:9c0655368b10ca4b2ffe39e4dd261fb89df25a46ae92d6eb4e6e1792a451883e: application/yaml
+

The displayed artifact tree shows that the original image (localhost:8080/busybox:latest) has one direct referrer (sha256:9c06...883e: application/yaml), the artifact yaml file.

Step 6: Sign the image and artifact

This step creates a key pair for cosign in a separate directory, then uses cosign to sign both the image and the artifact file. Both signatures, like the artifact file itself, are associated with the busybox image.

# create a key pair in a different directory
+pushd ${TEST_TMPDIR}
+COSIGN_PASSWORD= ${COSIGN} generate-key-pair
+popd
+# sign the image
+COSIGN_PASSWORD= COSIGN_OCI_EXPERIMENTAL=1 COSIGN_EXPERIMENTAL=1 ${COSIGN} sign -y --key ${TEST_TMPDIR}/cosign.key --registry-referrers-mode=oci-1-1 ${ZOT_HOST}:${ZOT_PORT}/busybox:latest
+# sign the artifact referring to the image
+COSIGN_PASSWORD= COSIGN_OCI_EXPERIMENTAL=1 COSIGN_EXPERIMENTAL=1 ${COSIGN} sign -y --key ${TEST_TMPDIR}/cosign.key --registry-referrers-mode=oci-1-1 ${ZOT_HOST}:${ZOT_PORT}/busybox@${REF0}
+

Step 7: Display the artifact tree

This step again prints the artifact tree, which should now show the artifact and the two signatures, all associated to the busybox image.

${REGCLIENT} artifact tree localhost:8080/busybox:latest
+

The following example shows the command and its output:

$ regctl artifact tree localhost:8080/busybox:latest
+
+Ref: localhost:8080/busybox:latest
+Digest: sha256:9172c5f692f2c65e4f773448503b21dba2de6454bd159905c4bf6d83176e4ea3
+Referrers:
+  - sha256:9c0655368b10ca4b2ffe39e4dd261fb89df25a46ae92d6eb4e6e1792a451883e: application/yaml
+    Referrers:
+      - sha256:06792b209137486442a2b804b2225c0014e3e238d363cdbea088bbd73207fb34: application/vnd.dev.cosign.artifact.sig.v1+json
+  - sha256:995b6a78bf04a7a9676dac76b4598ccb645c17e30b02f294de9fdfa2f28eb7b2: application/vnd.dev.cosign.artifact.sig.v1+json
+

The displayed artifact tree shows that the original image now has two direct referrers — the artifact and the cosign signature of the original image. In addition, there is a second-level referrer — the cosign signature of the artifact, which is a referrer of the artifact file.

Step 8: End of demonstration

This step halts the zot registry server, ending the workflow demonstration.

# function for stopping zot after demonstration
+function zot_teardown() {
+  killall zot
+}
+
+# stop zot
+zot_teardown
+

Reference: Full workflow script

Expand the text box below to view the entire workflow as a single executable shell script.

💡 To copy the script to the clipboard, click the copy icon that appears in the upper right corner of the expanded text box.

Click here to view the all-in-one script
#!/bin/bash -xe
+
+TEST_TMPDIR=$(mktemp -d "${PWD}/artifact-test-${1:+-$1}.XXXXXX")
+
+TOOLSDIR=$(pwd)/hack/tools
+mkdir -p ${TOOLSDIR}/bin
+
+REGCLIENT=${TOOLSDIR}/bin/regctl
+REGCLIENT_VERSION=v0.5.1
+curl -Lo ${REGCLIENT} https://github.com/regclient/regclient/releases/download/${REGCLIENT_VERSION}/regctl-linux-amd64
+chmod +x ${REGCLIENT}
+
+COSIGN=${TOOLSDIR}/bin/cosign
+COSIGN_VERSION=2.1.1
+curl -Lo ${COSIGN} https://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}/cosign-linux-amd64 
+chmod +x ${COSIGN}
+
+# OCI registry
+ZOT=${TOOLSDIR}/bin/zot
+ZOT_VERSION=2.0.0-rc6
+curl -Lo ${ZOT} https://github.com/project-zot/zot/releases/download/v${ZOT_VERSION}/zot-linux-amd64-minimal
+chmod +x ${ZOT}
+
+ZOT_HOST=localhost
+ZOT_PORT=8080
+
+function zot_setup() {
+cat > $TEST_TMPDIR/zot-config.json << EOF
+{
+  "distSpecVersion": "1.1.0-dev",
+  "storage": {
+      "rootDirectory": "$TEST_TMPDIR/zot"
+  },
+  "http": {
+      "address": "$ZOT_HOST",
+      "port": "$ZOT_PORT"
+  },
+  "log": {
+      "level": "error"
+  }
+}
+EOF
+# start as a background task
+${ZOT} serve $TEST_TMPDIR/zot-config.json &
+pid=$!
+        # wait until service is up
+count=5
+up=0
+while [[ $count -gt 0 ]]; do
+    if [ ! -d /proc/$pid ]; then
+    echo "zot failed to start or died"
+    exit 1
+    fi
+    up=1
+    curl -f http://$ZOT_HOST:$ZOT_PORT/v2/ || up=0
+    if [ $up -eq 1 ]; then break; fi
+    sleep 1
+    count=$((count - 1))
+done
+if [ $up -eq 0 ]; then
+    echo "Timed out waiting for zot"
+    exit 1
+fi
+# setup a OCI client
+${REGCLIENT} registry set --tls=disabled $ZOT_HOST:$ZOT_PORT
+}
+
+# function for stopping zot after demonstration
+function zot_teardown() {
+killall zot
+}
+
+# call the function to start zot
+zot_setup
+
+# copy an image
+skopeo copy --format=oci --dest-tls-verify=false docker://busybox:latest docker://${ZOT_HOST}:${ZOT_PORT}/busybox:latest
+
+# copy an artifact referring to the above image
+cat > ${TEST_TMPDIR}/artifact.yaml << EOF
+key:
+val: artifact
+EOF
+${REGCLIENT} artifact put --artifact-type application/yaml -f ${TEST_TMPDIR}/artifact.yaml --subject ${ZOT_HOST}:${ZOT_PORT}/busybox:latest
+REF0=$(${REGCLIENT} artifact tree --format '{{jsonPretty .}}' localhost:8080/busybox:latest | jq .referrer[0].reference.Digest)
+REF0="${REF0:1:-1}"
+
+# create a key pair in a different directory
+pushd ${TEST_TMPDIR}
+COSIGN_PASSWORD= ${COSIGN} generate-key-pair
+popd
+# sign the image
+COSIGN_PASSWORD= COSIGN_OCI_EXPERIMENTAL=1 COSIGN_EXPERIMENTAL=1 ${COSIGN} sign -y --key ${TEST_TMPDIR}/cosign.key --registry-referrers-mode=oci-1-1 ${ZOT_HOST}:${ZOT_PORT}/busybox:latest
+# sign the artifact referring to the image
+COSIGN_PASSWORD= COSIGN_OCI_EXPERIMENTAL=1 COSIGN_EXPERIMENTAL=1 ${COSIGN} sign -y --key ${TEST_TMPDIR}/cosign.key --registry-referrers-mode=oci-1-1 ${ZOT_HOST}:${ZOT_PORT}/busybox@${REF0}
+
+# list the reference tree
+${REGCLIENT} artifact tree localhost:8080/busybox:latest
+
+# stop zot
+zot_teardown
+

Last update: October 6, 2023
\ No newline at end of file diff --git a/v2.0.2/assets/images/504566.jpg b/v2.0.2/assets/images/504566.jpg new file mode 100644 index 0000000000000000000000000000000000000000..621abf631908d69e35724c00b930fdf25e67ea68 GIT binary patch literal 256139 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

-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 w7!?z{-O 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⪼OXY>9 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