Skip to content

Instantly share code, notes, and snippets.

@smoser
Last active April 26, 2023 23:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smoser/5a3623e497f90925ff4d9344a85c50a3 to your computer and use it in GitHub Desktop.
Save smoser/5a3623e497f90925ff4d9344a85c50a3 to your computer and use it in GitHub Desktop.
Running zot config and such

I run a local zot for use with stacker.

It is very useful to be able to publish oci images. It also can improve performance by acting as a caching proxy. See sync extension. This is especially useful due to docker.io's low bandwidth limits.

Quick start

To use this for localhost:

  • Download a zot from releases and make it executable (chmod 755 zot)

  • Generate a new certificates.

    ./generate-certs certs

  • Run the zot server

    ./zot serve config.yaml

If you want you can still

  • Get zli, the zot command line interface tool from releases and chmod it.

  • Configure zli:

    zli config add localhost https://127.0.0.1:5000/ verify-tls=false

Authentication

For local auth, use of http auth is the easiest thing. You can manage an htpasswd file with htpasswd from apache2-utils.

The htpasswd file here contains a user 'zot' with password 'zot'.

You can re-create it if you'd like, just remove it and then:

$ rm -f htpasswd.txt
$ htpasswd -cbB htpasswd.txt zot zot

You can add or update users with:

$ htpasswd -bB htpasswd.txt newuser newpassword

Delete users with:

$ htpasswd -D htpasswd.txt baduser

Certificates / SSL

If you want to have your SSL certificate trusted, then you either have to use a real certificate (signed by a real CA) or make your local system trust things signed by your local CA.

Add your your newly created Certificate Authority on ubuntu, (doc) like this:

$ sudo cp certs/ca.pem /usr/local/share/ca-certificates/localhost-zot.crt
$ sudo update-ca-certificates

Alternatively, to just tell container tools (like skopeo) not to require valid certificates, you can put the following into either /etc/containers/registries.conf or $HOME/.config/containers/registries.conf per containers-registries.conf(5).

[[registry]]
location = "localhost:5000"
insecure = true

Skopeo / populate your zot

Using skopeo with your local zot is an easy way to get some images into it. The usage looks something like:

skopeo copy --dest-creds="zot:zot" --dest-tls-verify \
    docker://ubuntu:latest \
    docker://localhost:5000/docker-sync/ubuntu:latest

If you have a real (or trusted) CA you can drop the '--dest-tls-verify'.

The sync-docker2zot script here will automate the syncing of some images into your local zot. Just run:

./sync-docker2zot
http:
# set this to literal 'address: ""' to listen on all interfaces.
# https://github.com/project-zot/zot/issues/1063
address: "127.0.0.1"
port: 5000
realm: "localhost-zot"
tls:
cert: certs/server-cert.pem
key: certs/server-key.pem
auth:
htpasswd:
path: "htpasswd.txt"
accessControl:
# by default, anonymous read. the zot user can read/write
"**":
anonymousPolicy: [read]
defaultPolicy: [read]
policies:
- users: [zot]
actions: [read, create, update, delete, detectManifestCollision]
log:
level: "debug"
audit: "logs/audit.log"
output: "logs/zot.log"
storage:
dedupe: true
rootdirectory: "storage"
extensions:
sync:
enable: true
registries:
- urls: ["https://docker.io/library"]
onDemand: true
tlsVerify: true
maxRetries: 6
retryDelay: "5m"
#!/bin/sh
# modified from generate-certs
# https://aci-github.cisco.com/gist/scmoser/5065a8f9314aaa43555cfd323eb2034a
# shellcheck disable=SC3043
fail() {
[ $# -eq 0 ] || stderr "$@"
exit 1
}
stderr() {
echo "$@" 1>&2
}
rq() {
local r="" out="" cmd=""
cmd="$*"
if command -v shell-quote >/dev/null 2>&1; then
cmd=$(shell-quote "$@") ||
{ stderr "shell-quote failed"; return 254; }
fi
stderr "execute: $cmd"
out=$("$@" 2>&1 </dev/null) && return 0
r=$?
stderr "$out"
stderr "failed [$r]"
return "$r"
}
gen_alt_ip_names() {
# generates IP:{base}.1,IP:{base}.2,....
local base="$1" n=1 buf=""
while [ $n -lt 254 ]; do
buf="$buf,IP:${base}.$n"
n=$((n+1))
done
echo "${buf#,}"
}
gen_key() {
local out="$1"
# we use '-traditional' here which generates a PKCS#1 format instead
# of the PKCS#8 format which is the default for openssl 3.0.2.
rq openssl genrsa -traditional -out "$out" 2048 ||
fail "failed to generate key into $out"
}
gen_request() {
# generate request, creates base-key.pem and base-req.pem
local subj="$1" key="$2" out="$3"
rq openssl req \
-new \
-key "$key" \
-nodes \
-out "$out" \
-subj "/$subj/" ||
fail "failed generating req for $subj"
}
gen_ca() {
local subj="$1" key="$2" out="$3"
rq openssl req \
-new \
-key "$key" \
-nodes \
-out "$out" \
-subj "/$subj/" \
-days $((365*20)) \
-x509 ||
fail "failed generating CA"
}
sign_request() {
local req="$1" cert="$2" key="$3" out="$4" extensions="$5"
rq openssl x509 \
-req \
-days $((365*20)) \
-sha256 \
-in "$req" \
-CA "$cert" \
-CAkey "$key" \
-CAcreateserial \
-out "$out" \
${extensions:+-extfile "${extensions}"} ||
fail "failed signing request from $req"
}
dir=${1:-"."}
[ -d "$dir" ] || mkdir "$dir" || fail "failed to create $dir"
cd "$dir" || fail "failed cd $dir"
stderr "Creating certificates in $PWD"
rm -f server-key.pem server-req.pem || fail "failed to remove server files"
hostname="$(hostname)"
caname="$(id -un)-ca"
osubs="DNS:localhost,IP:127.0.0.1"
osubs="$osubs,DNS:$hostname"
# losubs gets IP:127.0.2.1,...,IP:127.0.2.254
# the server-cert is signed by the ca to be valid for all of those IPs.
losubs=$(gen_alt_ip_names "127.0.2")
echo "subjectAltName=$osubs${losubs:+,$losubs}" > server-ext.txt
## generate x509 Certificate Authority to ca.pem and key ca-key.pem
if [ -f ca-key.pem ] && [ -f ca.pem ]; then
stderr "Re-using existing Certificate Authority"
else
stderr "Generating certificate authority for $caname"
gen_key ca-key.pem
gen_ca "CN=$caname" ca-key.pem ca.pem
fi
## generate server certificate request and key.
gen_key server-key.pem
gen_request "CN=server" server-key.pem server-req.pem
sign_request server-req.pem ca.pem ca-key.pem server-cert.pem server-ext.txt
## remove intermediate files
rm server-ext.txt server-req.pem || fail "failed cleanup"
zot:$2y$05$B77HgFEP7RgVqrXr0uQGsuBtlwseUZ9S6/C1mzdUdWtY4ZwlAnVIS
#!/bin/bash
# sync some docker images to zot
# for these docker urls, then you can save yourself from
# the docker bandwidth limit by just referencing
# * docker://localhost:5000/docker-sync/ubuntu:latest
#
# Run this with some frequency, as up to date images are good to have.
DOCKER_URLS=(
"docker://ubuntu:latest"
"docker://ubuntu:jammy"
"docker://centos:latest"
"docker://alpine:edge"
)
# Sync to a oci local directory to use less bandwidth from docker
# and also to resume more safely.
SYNC_OCI="oci:/tmp/sync-oci.d"
ZOT_CREDS=${ZOT_CREDS:-"zot:zot"}
ZOT_BASE="docker://localhost:5000/docker-sync"
fail() { echo "$@" 1>&2; exit 1; }
msg() { echo "$(date -R)" "$@"; }
mkdir -p "${SYNC_OCI#oci:}" ||
fail "failed to create ${SYNC_OCI} dir for local sync"
for dockurl in "${DOCKER_URLS[@]}"; do
base=${dockurl##*/}
ociurl="${SYNC_OCI}:$base"
msg "sync $dockurl -> $ociurl"
skopeo copy "$dockurl" "$ociurl" ||
fail "failed to sync $dockurl -> $ociurl"
done
for dockurl in "${DOCKER_URLS[@]}"; do
base=${dockurl##*/}
zoturl="${ZOT_BASE%/}/${base}"
ociurl="${SYNC_OCI}:$base"
msg "publish $ociurl -> $zoturl"
skopeo copy --dest-creds="$ZOT_CREDS" --dest-tls-verify \
"$ociurl" "$zoturl" ||
fail "failed to publish $ociurl -> $zoturl"
done
msg "done"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment