From 9fc7b4487b2a341866f6c3366c0d73a41f3dfce9 Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Thu, 16 Jul 2026 14:07:25 +0200 Subject: [PATCH] =?UTF-8?q?fix(infra):=20local=20compose=20parity=20?= =?UTF-8?q?=E2=80=94=20add=20domain=20+=20portals,=20wire=20host-browser?= =?UTF-8?q?=20OIDC=20(closes=20#91)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docker-compose.local.yml lacked the domain service and all three portals, and never wired host-browser OIDC. Add them, give the BFF its Keycloak/downstream env, and pin Keycloak's issuer to http://localhost:8180 with a dynamic backchannel so a host browser logs in on localhost:8180 while the BFF still validates in-network via keycloak:8080. Portals bind-mount a localhost:8180 config.json over the baked keycloak:8080 one. Co-Authored-By: Claude Opus 4.8 (1M context) --- infra/docker-compose.local.yml | 121 +++++++++++++++++++- infra/local-config/behandel.config.json | 3 + infra/local-config/self-service.config.json | 3 + 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 infra/local-config/behandel.config.json create mode 100644 infra/local-config/self-service.config.json diff --git a/infra/docker-compose.local.yml b/infra/docker-compose.local.yml index 18d3f68..e380b8d 100644 --- a/infra/docker-compose.local.yml +++ b/infra/docker-compose.local.yml @@ -17,7 +17,12 @@ # # Port map (host): # 8000 OpenZaak · 8001 Open Notificaties · 8080 BFF · 8090 Flowable REST -# 8100 ACL · 8180 Keycloak (all admin: admin / admin — dev only) +# 8100 ACL · 8130 Domain · 8180 Keycloak (all admin: admin / admin — dev only) +# 8140 self-service portal · 8141 openbaar register · 8142 behandel portal +# +# Portal OIDC on the HOST: browse the portals at their 8140/8141/8142 ports and log in via +# Keycloak on localhost:8180 (KC_HOSTNAME below pins the issuer there; the BFF still validates +# in-network via keycloak:8080). Test users are in docs/synthetic-data.md. services: @@ -205,6 +210,12 @@ services: KEYCLOAK_ADMIN_PASSWORD: admin KC_HEALTH_ENABLED: "true" KC_HTTP_ENABLED: "true" + # Pin the frontend/issuer URL to the host-published address so a browser on the host and the + # tokens it gets both use localhost:8180. KC_HOSTNAME_BACKCHANNEL_DYNAMIC lets in-network + # callers (the BFF via keycloak:8080) still resolve token/jwks endpoints to their request host, + # so the BFF validates the localhost:8180 issuer while fetching keys over the compose network. + KC_HOSTNAME: http://localhost:8180 + KC_HOSTNAME_BACKCHANNEL_DYNAMIC: "true" ports: - "8180:8080" volumes: @@ -295,6 +306,14 @@ services: context: ../services/bff dockerfile: Dockerfile image: register-referentie/bff:dev + environment: + # Reach Keycloak over the compose network for metadata/keys; the discovered issuer is the + # host-pinned localhost:8180 (KC_HOSTNAME above), which is what browser tokens carry — so + # validation matches without the BFF ever needing to resolve localhost:8180 itself. + Keycloak__Authority: http://keycloak:8080/realms/digid + Keycloak__MedewerkerAuthority: http://keycloak:8080/realms/medewerker + Downstream__Domain__BaseUrl: http://domain:8080/ + Downstream__Projection__BaseUrl: http://projection-api:8080/ ports: - "8080:8080" healthcheck: @@ -303,6 +322,39 @@ services: timeout: 3s retries: 5 start_period: 10s + depends_on: + domain: + condition: service_healthy + projection-api: + condition: service_healthy + keycloak: + condition: service_started + networks: [cg] + + # ── BIG Domain Service (S-05) ───────────────────────────────────────────── + domain: + build: + context: ../services/domain + dockerfile: Dockerfile + image: register-referentie/domain:dev + environment: + Flowable__BaseUrl: http://flowable-rest:8080/flowable-rest/ + Flowable__Username: rest-admin + Flowable__Password: test + Acl__BaseUrl: http://acl:8080/ + ports: + - "8130:8080" + healthcheck: + test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"] + interval: 5s + timeout: 3s + retries: 5 + start_period: 10s + depends_on: + acl: + condition: service_healthy + flowable-init: + condition: service_completed_successfully networks: [cg] # ── Read projection (S-06) ──────────────────────────────────────────────── @@ -362,6 +414,73 @@ services: condition: service_healthy networks: [cg] + # ── Portals (S-08/S-09/S-12) ────────────────────────────────────────────── + # nginx serves each Angular app and reverse-proxies its endpoint group to the BFF (same-origin). + # The images bake config.json with the compose authority (keycloak:8080), which a HOST browser + # can't resolve — so here we bind-mount a config.json pointing at the host-published localhost:8180 + # (matching KC_HOSTNAME). openbaar is anonymous and needs no config. + self-service: + build: + context: .. + dockerfile: apps/self-service/Dockerfile + image: register-referentie/self-service:dev + ports: + - "8140:80" + volumes: + - ./local-config/self-service.config.json:/usr/share/nginx/html/config.json:ro,z + healthcheck: + test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1/ || exit 1"] + interval: 5s + timeout: 3s + retries: 5 + start_period: 10s + depends_on: + bff: + condition: service_healthy + keycloak: + condition: service_started + networks: [cg] + + openbaar: + build: + context: .. + dockerfile: apps/openbaar/Dockerfile + image: register-referentie/openbaar:dev + ports: + - "8141:80" + healthcheck: + test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1/ || exit 1"] + interval: 5s + timeout: 3s + retries: 5 + start_period: 10s + depends_on: + bff: + condition: service_healthy + networks: [cg] + + behandel: + build: + context: .. + dockerfile: apps/behandel/Dockerfile + image: register-referentie/behandel:dev + ports: + - "8142:80" + volumes: + - ./local-config/behandel.config.json:/usr/share/nginx/html/config.json:ro,z + healthcheck: + test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1/ || exit 1"] + interval: 5s + timeout: 3s + retries: 5 + start_period: 10s + depends_on: + bff: + condition: service_healthy + keycloak: + condition: service_started + networks: [cg] + volumes: oz-db: nrc-db: diff --git a/infra/local-config/behandel.config.json b/infra/local-config/behandel.config.json new file mode 100644 index 0000000..71c0f65 --- /dev/null +++ b/infra/local-config/behandel.config.json @@ -0,0 +1,3 @@ +{ + "authority": "http://localhost:8180/realms/medewerker" +} diff --git a/infra/local-config/self-service.config.json b/infra/local-config/self-service.config.json new file mode 100644 index 0000000..7642cac --- /dev/null +++ b/infra/local-config/self-service.config.json @@ -0,0 +1,3 @@ +{ + "authority": "http://localhost:8180/realms/digid" +}