feat(openzaak): real secrets + TLS for the production OpenZaak harness (WP-55)
CI / changes (push) Successful in 8s
CI / lint (push) Successful in 12s
CI / frontend (push) Successful in 14s
CI / storybook-a11y (push) Successful in 17s
CI / backend (push) Successful in 1m51s
CI / semgrep (push) Successful in 1m13s
CI / e2e (push) Successful in 2m56s
CI / api-client-drift (push) Successful in 1m41s
CI / changes (push) Successful in 8s
CI / lint (push) Successful in 12s
CI / frontend (push) Successful in 14s
CI / storybook-a11y (push) Successful in 17s
CI / backend (push) Successful in 1m51s
CI / semgrep (push) Successful in 1m13s
CI / e2e (push) Successful in 2m56s
CI / api-client-drift (push) Successful in 1m41s
docker-compose.openzaak.prod.yml layers real SECRET_KEY/DB password/site
domain/allowed-hosts (all required, fail-fast via ${VAR:?...}) on top of the
WP-54 dev harness, switches Postgres off trust auth, and sets IS_HTTPS for a
front-facing reverse-proxy TLS setup. The ZGW client secret lives inside a
file setup_configuration reads rather than a compose env var, so it's
templated (data.prod.yaml.template, no secret) and rendered host-side via
render-prod-secrets.sh into a gitignored data.prod.yaml, mounted over the
container's dev data.yaml. ZgwOptions.cs already binds from IConfiguration,
so the BFF side needed no code change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,15 +105,15 @@ for its existing violations, so every WP ends green.
|
||||
| [WP-52](WP-52-openzaak-notificaties.md) | OpenZaak Notificaties (NRC) live status via webhook | 9 · OpenZaak/ZGW | done |
|
||||
| [WP-53](WP-53-inbound-identity-and-citizen-scoping.md) | Inbound identity seam + citizen-scoping (per-request BSN, ZGW audit claims) | 9 · OpenZaak/ZGW | done |
|
||||
| [WP-54](WP-54-openzaak-integration-harness.md) | Docker OpenZaak integration-test harness (opt-in, live round-trip) | 9 · OpenZaak/ZGW | done |
|
||||
| [WP-55](WP-55-openzaak-secrets-tls.md) | Real secrets + TLS for the OpenZaak harness | 10 · OpenZaak hardening | todo |
|
||||
| [WP-55](WP-55-openzaak-secrets-tls.md) | Real secrets + TLS for the OpenZaak harness | 10 · OpenZaak hardening | done |
|
||||
| [WP-56](WP-56-openzaak-catalogus-provisioning.md) | Idempotent catalogus provisioning | 10 · OpenZaak hardening | todo |
|
||||
| [WP-57](WP-57-openzaak-least-privilege-scopes.md) | Least-privilege client scopes | 10 · OpenZaak hardening | todo |
|
||||
| [WP-58](WP-58-openzaak-notifications.md) | Real notifications (celery + scripted abonnement) | 10 · OpenZaak hardening | todo |
|
||||
| [WP-59](WP-59-document-confidentialiteit-config.md) | Per-document-type confidentialiteit config | 10 · OpenZaak hardening | todo |
|
||||
| [WP-59](WP-59-document-confidentialiteit-config.md) | Per-document-type confidentialiteit config | 10 · OpenZaak hardening | todo |
|
||||
| [WP-60](WP-60-write-divergence-resilience.md) | Write-divergence resilience (local + ZGW writes) | 10 · OpenZaak hardening | todo |
|
||||
| [WP-61](WP-61-behandelportal-bootstrap.md) | Bootstrap the behandelportal app | 11 · Behandelportal | todo |
|
||||
| [WP-62](WP-62-medewerker-identity-authz.md) | Backend: medewerker caller identity + authz seam | 11 · Behandelportal | todo |
|
||||
| [WP-63](WP-63-aanvraag-status-lifecycle.md) | Backend: aanvraag status lifecycle as a published DTO | 11 · Behandelportal | todo |
|
||||
| [WP-62](WP-62-medewerker-identity-authz.md) | Backend: medewerker caller identity + authz seam | 11 · Behandelportal | todo |
|
||||
| [WP-63](WP-63-aanvraag-status-lifecycle.md) | Backend: aanvraag status lifecycle as a published DTO | 11 · Behandelportal | todo |
|
||||
| [WP-64](WP-64-behandelportal-werkvoorraad.md) | Behandelportal: werkvoorraad (queue) screen | 11 · Behandelportal | todo |
|
||||
| [WP-65](WP-65-behandelportal-beoordeling.md) | Behandelportal: zaak detail + beoordeling (decision) screen | 11 · Behandelportal | todo |
|
||||
| [WP-66](WP-66-behandelportal-openzaak-write.md) | Wire the decision into OpenZaak | 11 · Behandelportal | todo |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# WP-55 — Real secrets + TLS for the OpenZaak harness
|
||||
|
||||
Status: todo
|
||||
Status: done
|
||||
Phase: 10 — OpenZaak production hardening
|
||||
|
||||
## Why
|
||||
@@ -45,10 +45,35 @@ change, not application code.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] No secret value is hardcoded in any committed compose/config file.
|
||||
- [ ] The production compose fails fast (or docs state clearly) when secrets aren't
|
||||
- [x] No secret value is hardcoded in any committed compose/config file.
|
||||
- [x] The production compose fails fast (or docs state clearly) when secrets aren't
|
||||
supplied — no silent fallback to a real-looking default.
|
||||
- [ ] README documents exactly which env vars must be set and how TLS is terminated.
|
||||
- [x] README documents exactly which env vars must be set and how TLS is terminated.
|
||||
|
||||
## Deviation from the original plan
|
||||
|
||||
The WP's own "Files" section expected the secret to be parameterized directly inside
|
||||
`docker-compose.openzaak.yml`'s environment or a straight env-var override. That covers
|
||||
`SECRET_KEY`/DB password/`IS_HTTPS` fine (compose does key-based environment merging across
|
||||
`-f` files even though the base file writes some blocks as YAML mappings and others as
|
||||
anchors), but the ZGW client secret lives inside `setup_configuration/data.yaml`, a file
|
||||
OpenZaak's own `setup_configuration` management command reads — compose has no mechanism to
|
||||
interpolate env vars _inside_ a mounted file's contents. Solved by templating that one file
|
||||
(`data.prod.yaml.template`, no secret) + a tiny host-side `render-prod-secrets.sh`
|
||||
(`envsubst`, fail-fast via `${VAR:?...}`) that produces a gitignored `data.prod.yaml`, which
|
||||
`docker-compose.openzaak.prod.yml` mounts over the container's `data.yaml` (bind-mounting a
|
||||
single file inside an already bind-mounted read-only directory works fine in Docker/Podman —
|
||||
verified via `docker compose config` with the override applied). No new dependency: `envsubst`
|
||||
is part of `gettext`, already present on this machine.
|
||||
|
||||
Verified for real: `docker compose -f docker-compose.openzaak.yml -f
|
||||
docker-compose.openzaak.prod.yml config` succeeds with all required env vars set and both
|
||||
environment overrides (SECRET_KEY, DB password/auth method) present in the merged output;
|
||||
fails with a clear `${VAR:?...}` error when any is missing. `render-prod-secrets.sh` itself
|
||||
fails fast (tested) when `OPENZAAK_CLIENT_SECRET` etc. are unset, and its rendered
|
||||
`data.prod.yaml` was inspected and matched the template with real values substituted.
|
||||
`cd backend && dotnet test` (WP-54 harness untouched): 159/159 green. The dev harness
|
||||
(`docker-compose.openzaak.yml` alone, `setup_configuration/data.yaml`) is untouched.
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ read (this WP), the behandelportal needs it as the thing it advances (WP-65).
|
||||
- The DTO change is additive: the SSP's `pendingHerregistratie` boolean can be derived
|
||||
from the new status field (or kept as a computed convenience) so this ships with zero
|
||||
required FE behavior change — a pure backend + contract widening.
|
||||
- Only the status *value* is published here; any transition (advancing it) is a separate
|
||||
- Only the status _value_ is published here; any transition (advancing it) is a separate
|
||||
write endpoint, not part of this slice (that's WP-65's mutation).
|
||||
|
||||
## Files
|
||||
@@ -60,7 +60,7 @@ dashboard still shows the same pending/approved states it does today.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Any endpoint that *advances* the status (WP-65); the behandelportal consuming it (WP-64).
|
||||
Any endpoint that _advances_ the status (WP-65); the behandelportal consuming it (WP-64).
|
||||
|
||||
## Risks
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Phase: 11 — Behandelportal
|
||||
|
||||
The core case-treatment write path — a medewerker opens one aanvraag's detail (including
|
||||
its documents) and records a decision (goedkeuren/afwijzen/meer info opvragen), advancing
|
||||
the status lifecycle WP-63 published. This is the first genuinely new *write* capability
|
||||
the status lifecycle WP-63 published. This is the first genuinely new _write_ capability
|
||||
in the system beyond what the citizen SSP already does to itself.
|
||||
|
||||
## Read first
|
||||
|
||||
Reference in New Issue
Block a user