-
-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
323 lines (303 loc) · 13.1 KB
/
Copy pathdocker-compose.yml
File metadata and controls
323 lines (303 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# LiturgicalCalendar Infrastructure
# This Docker Compose file sets up Zitadel (identity provider) with Login V2, PostgreSQL,
# and OpenFGA (fine-grained authorization) for the RBAC and registration system.
#
# Usage:
# docker compose up -d # Start all services
# docker compose down # Stop all services
# docker compose logs -f zitadel # View Zitadel logs
# docker compose logs -f openfga # View OpenFGA logs
#
# After starting:
# Zitadel Console: http://localhost:8080/ui/console
# OpenFGA Playground: http://localhost:3001
# Default admin: root@LiturgicalCalendar.localhost / RootPassword1!
services:
zitadel:
restart: unless-stopped
image: ghcr.io/zitadel/zitadel:latest
# Master key for encryption (MUST be exactly 32 characters).
# Override in production via ZITADEL_MASTERKEY env var: generate with `openssl rand -hex 16`
command: 'start-from-init --masterkey "${ZITADEL_MASTERKEY:-MasterkeyNeedsToHave32Characters}"'
environment:
# See "What's next" to learn about how to serve Zitadel on a different domain or IP.
ZITADEL_EXTERNALDOMAIN: localhost
# See "What's next" to learn about how to enable TLS.
ZITADEL_EXTERNALSECURE: false
ZITADEL_TLS_ENABLED: false
# Database configuration
ZITADEL_DATABASE_POSTGRES_HOST: db
ZITADEL_DATABASE_POSTGRES_PORT: 5432
# The database is created by the init job if it does not exist
ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
# The admin user must already exist in the database.
ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres
ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: postgres
ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable
# The zitadel user is created by the init job if it does not exist.
ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: zitadel
ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable
# By configuring a login client, the setup job creates a user of type machine with the role IAM_LOGIN_CLIENT.
# It writes a PAT to the path specified in ZITADEL_FIRSTINSTANCE_LOGINCLIENTPATPATH.
# The PAT is passed to the login container via the environment variable ZITADEL_SERVICE_USER_TOKEN_FILE.
ZITADEL_FIRSTINSTANCE_LOGINCLIENTPATPATH: /current-dir/login-client.pat
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: false
ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_MACHINE_USERNAME: login-client
ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_MACHINE_NAME: Login V2 Client
ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_PAT_EXPIRATIONDATE: '2030-01-01T00:00:00Z'
# Enable Login V2 (default port 8081 to avoid conflict with Frontend dev server on 3000)
# Override ZITADEL_LOGIN_PORT in .env to change the Login V2 port
ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED: true
ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_BASEURI: http://localhost:${ZITADEL_LOGIN_PORT:-8081}/ui/v2/login
# Configure the redirection paths to the login v2.
ZITADEL_OIDC_DEFAULTLOGINURLV2: http://localhost:${ZITADEL_LOGIN_PORT:-8081}/ui/v2/login/login?authRequest=
ZITADEL_OIDC_DEFAULTLOGOUTURLV2: http://localhost:${ZITADEL_LOGIN_PORT:-8081}/ui/v2/login/logout?post_logout_redirect=
ZITADEL_SAML_DEFAULTLOGINURLV2: http://localhost:${ZITADEL_LOGIN_PORT:-8081}/ui/v2/login/login?samlRequest=
# By configuring a machine, the setup job creates a user of type machine with the role IAM_OWNER.
# It writes a personal access token (PAT) to the path specified in ZITADEL_FIRSTINSTANCE_PATPATH.
# The PAT can be used to provision resources with [Terraform](/docs/guides/manage/terraform-provider), for example.
ZITADEL_FIRSTINSTANCE_PATPATH: /current-dir/admin.pat
ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_USERNAME: admin
ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_NAME: Automatically Initialized IAM_OWNER
ZITADEL_FIRSTINSTANCE_ORG_MACHINE_PAT_EXPIRATIONDATE: '2030-01-01T00:00:00Z'
# To change the initial human admin users username and password, uncomment the following lines.
# The first login name is formatted like this: <username>@<org_name>.<external_domain>
# With the following incommented configuration, this would be root@my-organization.localhost
# Visit http://localhost:8080/ui/console to check if the login name works.
# If you can't log in, check the available login names:
# echo "select * from projections.login_names3;" | psql -h localhost -U postgres -d zitadel
# The postgres users password is postgres.
ZITADEL_FIRSTINSTANCE_ORG_NAME: "LiturgicalCalendar"
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME: root
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD: RootPassword1!
# SMTP configuration (Mailpit for local development)
ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST: mailpit:1025
ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_USER: ""
ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_PASSWORD: ""
ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_TLS: false
ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_FROM: noreply@liturgicalcalendar.localhost
ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_FROMNAME: LiturgicalCalendar
# Enable debug logs
ZITADEL_LOG_LEVEL: debug
# Write Access Logs to stdout.
ZITADEL_LOGSTORE_ACCESS_STDOUT_ENABLED: true
healthcheck:
test: ["CMD", "/app/zitadel", "ready"]
interval: 10s
timeout: 60s
retries: 5
start_period: 10s
user: "0"
volumes:
- .:/current-dir:delegated
ports:
- 127.0.0.1:${ZITADEL_PORT:-8080}:8080
- 127.0.0.1:${ZITADEL_LOGIN_PORT:-8081}:3000
networks:
- zitadel
depends_on:
db:
condition: service_healthy
mailpit:
condition: service_started
# Login V2 - Next.js based login UI with passkeys, flexible onboarding, etc.
login:
restart: unless-stopped
image: ghcr.io/zitadel/zitadel-login:latest
environment:
ZITADEL_API_URL: http://localhost:8080
NEXT_PUBLIC_BASE_PATH: /ui/v2/login
ZITADEL_SERVICE_USER_TOKEN_FILE: /current-dir/login-client.pat
EMAIL_VERIFICATION: true
healthcheck:
# Use Node.js (available in Next.js image) to check if the server responds
test:
- CMD
- node
- -e
- "const http = require('http'); const req = http.get('http://localhost:3000/ui/v2/login', (res) => { process.exit(res.statusCode === 200 ? 0 : 1); }); req.on('error', () => process.exit(1)); req.setTimeout(5000, () => { req.destroy(); process.exit(1); });"
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
network_mode: service:zitadel
user: "0"
volumes:
- .:/current-dir:ro
depends_on:
zitadel:
condition: service_healthy
restart: false
db:
restart: unless-stopped
image: postgres:17
environment:
PGUSER: postgres
POSTGRES_PASSWORD: postgres
healthcheck:
test:
- CMD-SHELL
- pg_isready
- -d
- zitadel
- -U
- postgres
interval: 10s
timeout: 30s
retries: 5
networks:
- zitadel
ports:
- 127.0.0.1:${DB_PORT:-5432}:5432
volumes:
- postgres_data:/var/lib/postgresql/data:rw
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
# One-shot Doctrine migrate runner for the litcal database.
# scripts/init-db.sql is bootstrap-only (roles, databases, pgcrypto, empty
# doctrine_migration_versions tracking table). Application-table DDL
# (access_requests, applications, api_keys, audit_log, ...) lives in
# src/Migrations/ and is applied by this service against the running db.
#
# Re-runnable: a no-op when everything is up-to-date. Always rebuild the
# image with `docker compose up -d --build` so newly-pulled migrations
# land in the container before this service runs.
#
# NOTE: this service exists so a fresh `docker compose up -d --build`
# from a wiped postgres_data volume produces a fully migrated schema
# with no manual `composer db:migrate` step. The API server itself
# still runs on the host via `composer start` — only migrations run
# in-container.
litcal-migrate:
build: .
command: ["php", "bin/doctrine-migrations", "migrate", "--no-interaction"]
environment:
DB_HOST: db
DB_PORT: 5432
DB_NAME: litcal
DB_USER: litcal
DB_PASSWORD: litcal_secure_password
depends_on:
db:
condition: service_healthy
networks:
- zitadel
restart: "no"
# Adminer - Database management UI
# Access at: http://localhost:8088
# Login: System=PostgreSQL, Server=db, Username=postgres, Password=postgres
adminer:
image: adminer:latest
restart: unless-stopped
ports:
- 127.0.0.1:${ADMINER_PORT:-8088}:8080
environment:
ADMINER_DEFAULT_SERVER: db
ADMINER_DESIGN: lucas-sandery
networks:
- zitadel
depends_on:
- db
# Mailpit - Email testing tool for local development
# Web UI at: http://localhost:8025
# SMTP server on port 1025 (internal, used by Zitadel)
mailpit:
image: axllent/mailpit:latest
restart: unless-stopped
ports:
- 127.0.0.1:${MAILPIT_PORT:-8025}:8025
environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
networks:
- zitadel
# OpenFGA - Fine-grained authorization engine (Google Zanzibar implementation)
# Provides relationship-based access control for calendar-specific permissions.
# HTTP API: http://localhost:3001 (Playground), http://localhost:8083 (API)
# Pin to a specific version for reproducible deployments.
openfga-migrate:
image: openfga/openfga:v1.18.2
command: migrate
environment:
OPENFGA_DATASTORE_ENGINE: postgres
OPENFGA_DATASTORE_URI: postgres://${OPENFGA_DB_USER:-openfga}:${OPENFGA_DB_PASSWORD:-openfga_secure_password}@db:5432/${OPENFGA_DB_NAME:-openfga}?sslmode=disable
networks:
- zitadel
depends_on:
db:
condition: service_healthy
openfga:
restart: unless-stopped
image: openfga/openfga:v1.18.2
command: run
environment:
OPENFGA_DATASTORE_ENGINE: postgres
OPENFGA_DATASTORE_URI: postgres://${OPENFGA_DB_USER:-openfga}:${OPENFGA_DB_PASSWORD:-openfga_secure_password}@db:5432/${OPENFGA_DB_NAME:-openfga}?sslmode=disable
# Secure-by-default: Playground UI is OFF and auth is OFF. Local dev should
# set OPENFGA_PLAYGROUND_ENABLED=true in .env.local to use the Playground.
# Production deployments must set OPENFGA_AUTHN_METHOD=preshared and
# OPENFGA_AUTHN_PRESHARED_KEYS=<key1>[,<key2>] (and configure the API with
# OPENFGA_API_TOKEN matching one of those keys).
OPENFGA_PLAYGROUND_ENABLED: "${OPENFGA_PLAYGROUND_ENABLED:-false}"
OPENFGA_AUTHN_METHOD: "${OPENFGA_AUTHN_METHOD:-none}"
OPENFGA_AUTHN_PRESHARED_KEYS: "${OPENFGA_AUTHN_PRESHARED_KEYS:-}"
healthcheck:
test: ["CMD", "/usr/local/bin/grpc_health_probe", "-addr=localhost:8081"]
interval: 10s
timeout: 30s
retries: 5
start_period: 10s
ports:
- 127.0.0.1:${OPENFGA_HTTP_PORT:-8083}:8080
- 127.0.0.1:${OPENFGA_GRPC_PORT:-8084}:8081
- 127.0.0.1:${OPENFGA_PLAYGROUND_PORT:-3001}:3000
networks:
- zitadel
depends_on:
openfga-migrate:
condition: service_completed_successfully
# Seeds the OpenFGA store + authorization model from cdcf-infra, which owns
# every model on the shared umbrella instance. This repo intentionally keeps
# no model file: a second copy is what let a stale model silently revert the
# deployed one in August 2026.
authz-seed:
image: alpine:3.21
restart: "no"
environment:
CDCF_INFRA_REF: "${CDCF_INFRA_REF:-main}"
# cdcf-infra's setup-openfga.sh requires a non-empty preshared key in the
# .env.local it sources regardless of target — it's only ever used as a
# single Bearer token, while OPENFGA_AUTHN_PRESHARED_KEYS is OpenFGA's own
# comma-separated list (<key1>[,<key2>]); the entrypoint below trims to
# the first key before writing .env.local. This stack's default
# OPENFGA_AUTHN_METHOD=none makes OpenFGA ignore the token entirely, so a
# placeholder is fine for local dev.
OPENFGA_PRESHARED_KEY: "${OPENFGA_AUTHN_PRESHARED_KEYS:-local-dev-preshared-key}"
entrypoint:
- /bin/sh
- -c
- |
set -eu
apk add --no-cache bash curl jq git >/dev/null
rm -rf /tmp/cdcf-infra
git clone --depth 1 --branch "$$CDCF_INFRA_REF" \
https://github.com/CatholicOS/cdcf-infra.git /tmp/cdcf-infra
cd /tmp/cdcf-infra/auth
OPENFGA_PRESHARED_KEY="$${OPENFGA_PRESHARED_KEY%%,*}"
cat > .env.local <<EOF
OPENFGA_API_URL=http://openfga:8080
OPENFGA_INTERNAL_URL=http://openfga:8080
OPENFGA_PRESHARED_KEY=$$OPENFGA_PRESHARED_KEY
EOF
./setup-openfga.sh --target local --create-litcal-store
networks:
- zitadel
depends_on:
openfga:
condition: service_healthy
networks:
zitadel:
driver: bridge
volumes:
postgres_data:
driver: local