Add Garage beside MinIO
All checks were successful
Deploy storage stack / deploy (push) Successful in 25s
All checks were successful
Deploy storage stack / deploy (push) Successful in 25s
MinIO is abandoned upstream and its images are gone from the registries, so the object store cannot be rebuilt or updated. Garage takes its place. This is the first step: Garage runs as one node next to MinIO, with the same three buckets and one key per app, and is not routed yet. MinIO keeps serving s3.asxp.io and is no longer bootstrapped, so its users stay as they are until the data is copied and the apps are switched. Garage only accepts keys in its own format. The bootstrap hashes the existing secrets into that format, as the apps' deploys will, so no secret has to change for the move; a secret already in Garage's format is used as it is. Garage has no anonymous S3 access. The public bucket is marked as a website instead, to be served through Garage's web endpoint. Assisted-by: Claude:fable-5-2
This commit is contained in:
parent
5619e8e11b
commit
dc04ff3cce
4 changed files with 171 additions and 23 deletions
103
init/garage-bootstrap.sh
Normal file
103
init/garage-bootstrap.sh
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#!/bin/sh
|
||||
# Idempotent Garage bootstrap, run on the host after `docker compose up`:
|
||||
# buckets, per-app keys and what each key may do. The Garage image has no
|
||||
# shell, so this drives its CLI through `docker exec`.
|
||||
#
|
||||
# Env: ASXPIO_S3_ACCESS_KEY/_SECRET_KEY (required), BINGO_S3_* and
|
||||
# PUBLIC_S3_* (optional). GARAGE_CONTAINER overrides the container name.
|
||||
set -eu
|
||||
|
||||
c="${GARAGE_CONTAINER:-storage-garage}"
|
||||
g() { docker exec "$c" /garage "$@"; }
|
||||
|
||||
# Garage only takes its own key format: an id of GK + 24 hex digits and a
|
||||
# secret of 64 hex digits. A value already in that format is used as it is;
|
||||
# anything else (the MinIO-era secrets) is hashed into it, the same way the
|
||||
# apps' deploy workflows do, so the secrets did not have to change with the
|
||||
# move. Replace a secret with a native Garage pair whenever it is rotated.
|
||||
garage_key_id() {
|
||||
if printf '%s' "$1" | grep -Eq '^GK[0-9a-f]{24}$'; then
|
||||
printf '%s' "$1"
|
||||
else
|
||||
printf 'GK%s' "$(printf '%s' "$1" | sha256sum | cut -c1-24)"
|
||||
fi
|
||||
}
|
||||
garage_secret() {
|
||||
if printf '%s' "$1" | grep -Eq '^[0-9a-f]{64}$'; then
|
||||
printf '%s' "$1"
|
||||
else
|
||||
printf '%s' "$1" | sha256sum | cut -c1-64
|
||||
fi
|
||||
}
|
||||
|
||||
i=0
|
||||
until g status >/dev/null 2>&1; do
|
||||
i=$((i + 1))
|
||||
if [ "$i" -gt 60 ]; then
|
||||
echo "garage-init: garage did not come up" >&2
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
ensure_bucket() {
|
||||
g bucket info "$1" >/dev/null 2>&1 || g bucket create "$1" >/dev/null
|
||||
}
|
||||
|
||||
# $1 name, $2 access key, $3 secret key. Prints the Garage key id.
|
||||
ensure_key() {
|
||||
id="$(garage_key_id "$2")"
|
||||
secret="$(garage_secret "$3")"
|
||||
if g key info --show-secret "$id" >/dev/null 2>&1; then
|
||||
if ! g key info --show-secret "$id" | grep -q "$secret"; then
|
||||
# Rotated secret under the same id.
|
||||
g key delete --yes "$id" >/dev/null
|
||||
g key import --yes -n "$1" "$id" "$secret" >/dev/null
|
||||
fi
|
||||
else
|
||||
g key import --yes -n "$1" "$id" "$secret" >/dev/null
|
||||
fi
|
||||
printf '%s' "$id"
|
||||
}
|
||||
|
||||
# $1 bucket, $2 key id, $3 "rw", "ro" or "wo". Sets exactly that.
|
||||
grant() {
|
||||
case "$3" in
|
||||
rw) g bucket allow --read --write "$1" --key "$2" >/dev/null
|
||||
g bucket deny --owner "$1" --key "$2" >/dev/null ;;
|
||||
ro) g bucket allow --read "$1" --key "$2" >/dev/null
|
||||
g bucket deny --write --owner "$1" --key "$2" >/dev/null ;;
|
||||
wo) g bucket allow --write "$1" --key "$2" >/dev/null
|
||||
g bucket deny --read --owner "$1" --key "$2" >/dev/null ;;
|
||||
esac
|
||||
}
|
||||
|
||||
ensure_bucket "asxpio-invoices"
|
||||
# Datacenter bingo photos: uploaded and resized by asxpio's admin, served by
|
||||
# datacenterbingo.
|
||||
ensure_bucket "datacenterbingo-photos"
|
||||
# Files shared by link: https://s3.asxp.io/public/<key>. Everything in this
|
||||
# bucket is readable by anyone who knows the key; nobody can list it.
|
||||
ensure_bucket "public"
|
||||
g bucket website --allow public >/dev/null
|
||||
|
||||
asxpio="$(ensure_key asxpio "${ASXPIO_S3_ACCESS_KEY}" "${ASXPIO_S3_SECRET_KEY}")"
|
||||
grant "asxpio-invoices" "$asxpio" rw
|
||||
grant "datacenterbingo-photos" "$asxpio" rw
|
||||
|
||||
if [ -n "${BINGO_S3_ACCESS_KEY:-}" ] && [ -n "${BINGO_S3_SECRET_KEY:-}" ]; then
|
||||
bingo="$(ensure_key bingo "${BINGO_S3_ACCESS_KEY}" "${BINGO_S3_SECRET_KEY}")"
|
||||
grant "datacenterbingo-photos" "$bingo" ro
|
||||
else
|
||||
echo "garage-init: BINGO_S3_* unset, skipping bingo key"
|
||||
fi
|
||||
|
||||
# Put and delete only: the holder can publish and retract, not read or list.
|
||||
if [ -n "${PUBLIC_S3_ACCESS_KEY:-}" ] && [ -n "${PUBLIC_S3_SECRET_KEY:-}" ]; then
|
||||
uploader="$(ensure_key public-upload "${PUBLIC_S3_ACCESS_KEY}" "${PUBLIC_S3_SECRET_KEY}")"
|
||||
grant "public" "$uploader" wo
|
||||
else
|
||||
echo "garage-init: PUBLIC_S3_* unset, skipping public uploader"
|
||||
fi
|
||||
|
||||
echo "garage-init: done"
|
||||
Loading…
Add table
Add a link
Reference in a new issue