Compare commits

..
Author SHA1 Message Date
Admin 7e9e90c3ba Use Ping's own credentials on the shared services
Infrastructure now gives each project its own Postgres role, S3 identity
limited to its bucket and a Zitadel service account that owns only its
project, instead of handing out the admin accounts.

- Postgres and S3 settings default to Ping's own (ping).
- zitadel-init mounts ZITADEL_PAT_DIR (Infrastructure's
  zitadel/.output/ping), waits for that PAT and uses it. It no longer
  creates the Zitadel project, which that account can't do:
  Infrastructure does.
2026-09-24 17:05:24 +02:00
4 changed files with 35 additions and 29 deletions
+1 -1
View File
@@ -54,7 +54,7 @@ in place:
```bash
cp backend/deploy/.env.example backend/deploy/.env
# edit backend/deploy/.env if your Infrastructure checkout isn't where
# ZITADEL_ADMIN_PAT_DIR assumes, or its S3 keys differ from the defaults
# ZITADEL_PAT_DIR assumes, or its PING_* credentials differ from the defaults
docker compose -f backend/deploy/compose.yml -f backend/deploy/compose.dev.yml up -d
```
+17 -13
View File
@@ -4,9 +4,11 @@
# cp deploy/.env.example deploy/.env
#
# Requires ../../../Infrastructure running first (Postgres, Zitadel,
# SeaweedFS). See ../../../Infrastructure/README.md. Everything marked
# "must match Infrastructure's .env" below has to be the same value as the
# one in that file.
# SeaweedFS). See ../../../Infrastructure/README.md. Ping has its own
# credentials on each shared service (role, S3 identity, Zitadel service
# account), provisioned by Infrastructure. Every value marked
# "= Infrastructure's PING_*" below has to be the same as that setting in
# Infrastructure's .env.
DOTNET_ENVIRONMENT=Development
@@ -16,17 +18,18 @@ PUBLIC_API_URL=http://localhost:5211
PUBLIC_AUTH_URL=http://host.docker.internal:8080
# --- PostgreSQL (Infrastructure's shared instance, Ping's own database) -----
# POSTGRES_USER / POSTGRES_PASSWORD must match Infrastructure's .env.
# Ping's own role, owner of ping_db only.
POSTGRES_HOST=host.docker.internal
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_USER=ping
# = Infrastructure's PING_DB_PASSWORD
POSTGRES_PASSWORD=ping
POSTGRES_DB=ping_db
# --- Zitadel (OIDC, shared instance) -----------------------------------------
# Path to the admin service-account PAT Infrastructure's Zitadel writes on
# init. Adjust if your Infrastructure checkout lives somewhere else relative
# to this one.
ZITADEL_ADMIN_PAT_DIR=../../../Infrastructure/zitadel/.output
# Folder with Ping's own Zitadel PAT (a service account that owns the Ping
# project only), written by Infrastructure's `provision`. Adjust if your
# Infrastructure checkout lives somewhere else relative to this one.
ZITADEL_PAT_DIR=../../../Infrastructure/zitadel/.output/ping
ZITADEL_DEV_MODE=true
# OIDC clients: the zitadel-init one-shot service (see compose.yml) fills these in
@@ -35,9 +38,10 @@ AUTH_CLIENT_ID=
WEB_CLIENT_ID=
# --- SeaweedFS (S3, shared instance, Ping's own bucket) ----------------------
# S3_ACCESS_KEY / S3_SECRET_KEY must match Infrastructure's .env.
S3_ACCESS_KEY=admin_access_key
S3_SECRET_KEY=admin_secret_key
# Ping's own identity, limited to S3_BUCKET.
# = Infrastructure's PING_S3_ACCESS_KEY / PING_S3_SECRET_KEY
S3_ACCESS_KEY=ping_access_key
S3_SECRET_KEY=ping_secret_key
S3_BUCKET=ping-storage
S3_PUBLIC_URL=http://host.docker.internal:8333
S3_USE_HTTP=true
+2 -2
View File
@@ -7,8 +7,8 @@ up first (see its own README for the exact command).
```bash
cp deploy/.env.example deploy/.env
# edit deploy/.env if your Infrastructure checkout isn't where
# ZITADEL_ADMIN_PAT_DIR assumes, or if its S3_ACCESS_KEY/SECRET_KEY differ
# from the defaults
# ZITADEL_PAT_DIR assumes, or if its PING_* credentials differ from the
# defaults
docker compose -f deploy/compose.yml -f deploy/compose.dev.yml up -d
```
+15 -13
View File
@@ -1,7 +1,8 @@
# Ping: base stack, shared by development and production.
#
# Zitadel and SeaweedFS are NOT run here: Ping reuses the shared instances in
# ../../../Infrastructure (see .env.example, ZITADEL_ADMIN_PAT_DIR / S3_*).
# ../../../Infrastructure (see .env.example, ZITADEL_PAT_DIR / S3_*), with
# Ping's own credentials on each (provisioned there).
# Bring that stack up first.
#
# dev docker compose -f deploy/compose.yml -f deploy/compose.dev.yml up -d
@@ -72,7 +73,7 @@ services:
image: alpine:3.20
container_name: ping-zitadel-init
volumes:
- ${ZITADEL_ADMIN_PAT_DIR}:/zitadel-output:ro
- ${ZITADEL_PAT_DIR}:/zitadel-output:ro
- ./.env:/workspace/.env
environment:
PUBLIC_AUTH_URL: ${PUBLIC_AUTH_URL}
@@ -99,11 +100,14 @@ services:
fi
}
if [ ! -f /zitadel-output/admin-sa.pat ]; then
echo "admin-sa.pat not found under ZITADEL_ADMIN_PAT_DIR. Is Infrastructure's Zitadel running?" >&2
exit 1
fi
PAT=$$(tr -d '\r\n' </zitadel-output/admin-sa.pat)
# Ping's own service account, owner of the Ping project only
# (created by Infrastructure's `provision`, see its README).
deadline=$$(( $$(date +%s) + 180 ))
while [ ! -s /zitadel-output/zitadel.pat ]; do
[ "$$(date +%s)" -lt "$$deadline" ] || { echo "no zitadel.pat in ZITADEL_PAT_DIR. Is Infrastructure up, and does ZITADEL_PAT_DIR point at its zitadel/.output/ping? Check 'docker logs infra-provision'." >&2; exit 1; }
sleep 3
done
PAT=$$(tr -d '\r\n' </zitadel-output/zitadel.pat)
MGMT="$$PUBLIC_AUTH_URL/management/v1"
echo "==> waiting for Zitadel to answer at $$PUBLIC_AUTH_URL"
@@ -124,13 +128,11 @@ services:
echo "==> project"
PROJECT_NAME=Ping
# Created by Infrastructure's `provision`: this account can't create
# projects, only manage this one.
PROJECT_ID=$$(api_call POST /projects/_search "$$(name_query "$$PROJECT_NAME")" | jq -r --arg n "$$PROJECT_NAME" '.result // [] | map(select(.name==$$n)) | first | .id // empty')
if [ -z "$$PROJECT_ID" ]; then
PROJECT_ID=$$(api_call POST /projects "$$(printf '{"name":"%s"}' "$$PROJECT_NAME")" | jq -r '.id')
echo " created (id $$PROJECT_ID)"
else
echo " reused (id $$PROJECT_ID)"
fi
[ -n "$$PROJECT_ID" ] || { echo "Zitadel project $$PROJECT_NAME not found. Is ping in Infrastructure's x-projects?" >&2; exit 1; }
echo " found (id $$PROJECT_ID)"
find_app() { api_call POST "/projects/$$PROJECT_ID/apps/_search" "$$(name_query "$$1")" | jq -r --arg n "$$1" '.result // [] | map(select(.name==$$n)) | first | .id // empty'; }