Files
SharedServices/provision/seaweedfs-s3-config.sh
T
Admin 33bf75d245 Give every project its own credentials on the shared services
Every project used the Postgres superuser, the RabbitMQ administrator, an
admin S3 identity and the Zitadel instance-admin PAT, so any one of them
could read or change the others' data.

A new one-shot, `provision` (runs on every `up`, idempotent), gives each
project in x-projects its own:

- Postgres role, owner of its database. No database is open to PUBLIC
  anymore, so a role can only connect to its own. An existing database
  and everything in it is handed over to the project's role.
- RabbitMQ user, with permissions on its own vhost only.
- Zitadel service account, PROJECT_OWNER of its own project only; its
  PAT is written to zitadel/.output/<project>/ for that project's
  zitadel-init to mount instead of the admin PAT.

SeaweedFS renders one S3 identity per project, limited to its bucket, and
refuses to start with a clear message on a malformed or repeated key.

The admin accounts stay with this stack. postgres-init is gone: provision
creates the databases. *.sh files are checked out with LF so they run in
the Linux containers from a Windows checkout.
2026-09-24 17:05:12 +02:00

61 lines
2.3 KiB
Bash

#!/bin/sh
# Prints SeaweedFS's S3 identity config (JSON) from the environment:
#
# infra S3_ACCESS_KEY / S3_SECRET_KEY, admin on every bucket (for
# operating the stack, not for projects)
# <project> <PROJECT>_S3_ACCESS_KEY / _SECRET_KEY, limited to the bucket
# <PROJECT>_S3_BUCKET (it may create it, nothing else)
#
# A project without keys gets no identity. Runs in the SeaweedFS container on
# every start, so the credentials can't drift from the env file.
set -eu
upper() { echo "$1" | tr '[:lower:]' '[:upper:]'; }
setting() { eval "printf '%s' \"\${$(upper "$1")_$2:-}\""; }
# The values go into JSON as they are: keep them to characters that need no
# escaping (what `openssl rand -hex` / -base64 produce).
check() {
case "$2" in
'' | *[!A-Za-z0-9_+/=.-]*) echo "seaweedfs-s3-config: $1 must be non-empty and only use A-Z a-z 0-9 _ + / = . -" >&2; exit 1 ;;
esac
}
identity() {
printf ' {"name": "%s", "credentials": [{"accessKey": "%s", "secretKey": "%s"}], "actions": [%s]}' "$1" "$2" "$3" "$4"
}
# SeaweedFS refuses to start (and keeps restarting) on a repeated access key,
# e.g. two values left at CHANGE_ME: say which ones instead.
seen=" "
unique() {
case "$seen" in
*" $2 "*) echo "seaweedfs-s3-config: $1 repeats an access key already used above; every identity needs its own" >&2; exit 1 ;;
esac
seen="$seen$2 "
}
check S3_ACCESS_KEY "$S3_ACCESS_KEY"
unique S3_ACCESS_KEY "$S3_ACCESS_KEY"
check S3_SECRET_KEY "$S3_SECRET_KEY"
printf '{\n "identities": [\n'
identity infra "$S3_ACCESS_KEY" "$S3_SECRET_KEY" '"Admin", "Read", "Write"'
for project in $PROJECTS; do
access=$(setting "$project" S3_ACCESS_KEY)
[ -n "$access" ] || continue
secret=$(setting "$project" S3_SECRET_KEY)
bucket=$(setting "$project" S3_BUCKET)
prefix=$(upper "$project")
check "${prefix}_S3_ACCESS_KEY" "$access"
check "${prefix}_S3_SECRET_KEY" "$secret"
check "${prefix}_S3_BUCKET" "$bucket"
unique "${prefix}_S3_ACCESS_KEY" "$access"
# Admin:<bucket> is what lets it create (and configure) that one bucket.
printf ',\n'
identity "$project" "$access" "$secret" \
"\"Admin:$bucket\", \"Read:$bucket\", \"Write:$bucket\", \"List:$bucket\", \"Tagging:$bucket\""
echo "seaweedfs-s3-config: $project -> bucket $bucket" >&2
done
printf '\n ]\n}\n'