Remove MinIO
All checks were successful
Deploy storage stack / deploy (push) Successful in 20s

Garage serves all three buckets and both apps, and a last comparison
found nothing in MinIO that Garage lacks. Drop the MinIO service, its
bootstrap and its root credentials from the deploy, and let compose
remove the leftover containers.

The storage_minio_data volume is left on the host. All images can be
pulled again, so the deploy goes back to failing on a pull error.

Document Garage in the README and SECRETS, including the key format and
how the existing secrets map to it, and swap the MinIO client in the
flake for awscli and rclone.

Assisted-by: Claude:fable-5-2
This commit is contained in:
Sergei Poljanski 2026-11-11 03:55:18 +04:00
commit e9388c0b0d
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
6 changed files with 74 additions and 231 deletions

View file

@ -1,148 +0,0 @@
#!/bin/sh
# Idempotent MinIO bootstrap: bucket + per-app service account scoped to that
# bucket. Re-running just refreshes the policy and resets the access key.
set -eu
mc alias set local http://minio:9000 "${MINIO_ROOT_USER}" "${MINIO_ROOT_PASSWORD}"
ensure_bucket() {
bucket="$1"
if ! mc ls "local/${bucket}" >/dev/null 2>&1; then
mc mb "local/${bucket}"
fi
mc anonymous set none "local/${bucket}" >/dev/null
}
write_policy() {
name="$1"
bucket="$2"
cat > "/tmp/${name}.json" <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetBucketLocation"],
"Resource": ["arn:aws:s3:::${bucket}"]
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::${bucket}/*"]
}
]
}
EOF
mc admin policy create local "${name}" "/tmp/${name}.json" 2>/dev/null \
|| mc admin policy update local "${name}" "/tmp/${name}.json"
}
# Read-only on one prefix of a bucket.
write_ro_prefix_policy() {
name="$1"
bucket="$2"
prefix="$3"
cat > "/tmp/${name}.json" <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::${bucket}/${prefix}*"]
}
]
}
EOF
mc admin policy create local "${name}" "/tmp/${name}.json" 2>/dev/null \
|| mc admin policy update local "${name}" "/tmp/${name}.json"
}
# World-readable by object key; no anonymous listing or writes.
ensure_public_bucket() {
bucket="$1"
if ! mc ls "local/${bucket}" >/dev/null 2>&1; then
mc mb "local/${bucket}"
fi
cat > "/tmp/${bucket}-anonymous.json" <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": ["*"]},
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::${bucket}/*"]
}
]
}
EOF
mc anonymous set-json "/tmp/${bucket}-anonymous.json" "local/${bucket}" >/dev/null
}
# Put and delete only: the holder can publish and retract, not read or list.
write_upload_policy() {
name="$1"
bucket="$2"
cat > "/tmp/${name}.json" <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::${bucket}/*"]
}
]
}
EOF
mc admin policy create local "${name}" "/tmp/${name}.json" 2>/dev/null \
|| mc admin policy update local "${name}" "/tmp/${name}.json"
}
# $3: one or more policy names, space-separated.
ensure_user() {
access="$1"
secret="$2"
policies="$3"
if mc admin user info local "${access}" >/dev/null 2>&1; then
# Rotate secret to match desired state.
mc admin user remove local "${access}" >/dev/null
fi
mc admin user add local "${access}" "${secret}"
# shellcheck disable=SC2086 # word-split the policy list on purpose
mc admin policy attach local ${policies} --user "${access}" 2>/dev/null || true
}
ensure_bucket "asxpio-invoices"
write_policy "asxpio-invoices-rw" "asxpio-invoices"
# Datacenter bingo photos: uploaded and resized by asxpio's admin, served by
# datacenterbingo. Keys keep their bingo/ prefix, so DB rows stay valid.
ensure_bucket "datacenterbingo-photos"
write_policy "datacenterbingo-photos-rw" "datacenterbingo-photos"
write_ro_prefix_policy "datacenterbingo-photos-ro" "datacenterbingo-photos" ""
ensure_user "${ASXPIO_S3_ACCESS_KEY}" "${ASXPIO_S3_SECRET_KEY}" "asxpio-invoices-rw datacenterbingo-photos-rw"
if [ -n "${BINGO_S3_ACCESS_KEY:-}" ] && [ -n "${BINGO_S3_SECRET_KEY:-}" ]; then
ensure_user "${BINGO_S3_ACCESS_KEY}" "${BINGO_S3_SECRET_KEY}" "datacenterbingo-photos-ro"
else
echo "minio-init: BINGO_S3_* unset, skipping bingo user"
fi
# Files shared by link: https://s3.asxp.io/public/<key>. Everything in this
# bucket is readable by anyone who knows the key.
ensure_public_bucket "public"
write_upload_policy "public-upload" "public"
if [ -n "${PUBLIC_S3_ACCESS_KEY:-}" ] && [ -n "${PUBLIC_S3_SECRET_KEY:-}" ]; then
ensure_user "${PUBLIC_S3_ACCESS_KEY}" "${PUBLIC_S3_SECRET_KEY}" "public-upload"
else
echo "minio-init: PUBLIC_S3_* unset, skipping public uploader"
fi
# Leftover from before the photos had their own bucket.
mc admin policy remove local "asxpio-invoices-bingo-ro" >/dev/null 2>&1 || true
echo "minio-init: done"