@@ -205,6 +205,23 @@ and now want to see it in action, please follow the following steps to build and
205205
206206 For this, both the EDC-V and CFM docker images must be built locally!!
207207
208+ #### 2.3 Build and deploy clearglass
209+
210+ Clearglass is a small Rust application that acts as a reverse proxy for the JAD services and is described in more
211+ detail in a [ later chapter] ( #jads-apis--a-single-pane-of-glass ) . It is being deployed as part of the base (or
212+ infrastructure)
213+ layer.
214+
215+ For now, we have to build and load it manually using the following commands:
216+
217+ ``` shell
218+ docker buildx build -f clearglass/Dockerfile -t ghcr.io/metaform/jad/clearglass:latest clearglass
219+ kind load docker-image -n jad ghcr.io/metaform/jad/clearglass:latest
220+ ```
221+
222+ _ Note that in a later evolution of JAD clearglass will be moved into its own repository which will make this step
223+ obsolete._
224+
208225### 3. Deploy the services
209226
210227JAD uses plain Kubernetes manifests to deploy the services. All the manifests are located in the [ k8s] ( ./k8s ) folder.
@@ -399,6 +416,76 @@ For example, if a participant onboarding went only through half-way, we recommen
399416
400417In some cases, even deleting and re-creating the KinD cluster may be required.
401418
419+ ## JAD's APIs – A single pane of glass
420+
421+ All JAD services are exposed through a single Traefik gateway (` edcv-gateway ` ) on ` jad.localhost ` , acting as a single
422+ pane of glass. Each service is reachable via a path prefix that is rewritten before forwarding to the backend.
423+
424+ Authentication is enforced at the gateway level using Traefik ` ForwardAuth ` middlewares. Each middleware forwards the
425+ ` Authorization ` header to the ` clearglass ` service, which validates the Bearer token against Keycloak via RFC 7662
426+ token introspection and checks for the required OAuth2 scopes. Services without a ` middleware ` entry listed are
427+ unauthenticated at the gateway level.
428+
429+ ### Application routes (` jad.localhost ` )
430+
431+ | Service | Exposed path | Rewrites to | Backend port | Auth middleware |
432+ | ---------------------| ---------------------| -------------------------| --------------| ----------------------------------------|
433+ | Control Plane | ` /api/management ` | ` /api/mgmt ` | ` 8081 ` | ` jwt-auth-management-api ` |
434+ | Identity Hub | ` /api/identity ` | ` /api/identity/v1alpha ` | ` 7081 ` | ` jwt-auth-identity-api ` |
435+ | Issuer Service | ` /api/issuer/admin ` | ` /api/admin/v1alpha ` | ` 10013 ` | ` jwt-auth-issuer-admin-api ` |
436+ | Provision Manager | ` /api/pm ` | ` /api/v1alpha ` | ` 8080 ` | ` jwt-auth-provision-manager-api ` |
437+ | Tenant Manager | ` /api/tm ` | ` /api/v1alpha1 ` | ` 8080 ` | ` jwt-auth-tenant-manager-api ` |
438+ | Dataplane (public) | ` /api/dp/public ` | ` / ` | ` 11002 ` | — |
439+ | Dataplane (control) | ` /api/dp/control ` | ` / ` | ` 8083 ` | — |
440+ | Dataplane (certs) | ` /api/dp/certs ` | ` / ` | ` 8186 ` | — |
441+ | Siglet | ` /api/siglet ` | ` / ` | ` 8080 ` | — |
442+ | Redline | ` /redline ` | ` / ` | ` 8081 ` | — |
443+ | Keycloak | ` /auth ` | ` / ` | ` 8080 ` | — (is the auth server) |
444+ | Web UI | ` /ui ` | ` / ` | ` 80 ` | — (obtains its own token via Keycloak) |
445+
446+ ### Auth middleware scopes
447+
448+ Each ` jwt-auth-* ` middleware enforces a specific pair of OAuth2 scopes (` read ` and ` write ` ):
449+
450+ | Middleware | Required scopes |
451+ | ----------------------------------| -------------------------------------------------------------|
452+ | ` jwt-auth-management-api ` | ` management-api:read ` , ` management-api:write ` |
453+ | ` jwt-auth-identity-api ` | ` identity-api:read ` , ` identity-api:write ` |
454+ | ` jwt-auth-issuer-admin-api ` | ` issuer-admin-api:read ` , ` issuer-admin-api:write ` |
455+ | ` jwt-auth-provision-manager-api ` | ` provision-manager-api:read ` , ` provision-manager-api:write ` |
456+ | ` jwt-auth-tenant-manager-api ` | ` tenant-manager-api:read ` , ` tenant-manager-api:write ` |
457+
458+ ### Infrastructure routes (each on their own hostname)
459+
460+ Infrastructure services are not protected by the auth middleware and are only intended for local development access.
461+
462+ | Service | Hostname | Remark |
463+ | ------------| ------------------------| ----------------------------------------------------------------|
464+ | Grafana | ` grafana.localhost ` | |
465+ | Prometheus | ` prometheus.localhost ` | |
466+ | Jaeger | ` jaeger.localhost ` | |
467+ | Loki | ` loki.localhost ` | |
468+ | Vault | ` vault.localhost ` | access from outside the cluster is only intended for e2e tests |
469+
470+ ### Clearglass
471+
472+ ` clearglass ` is a small sidecar service (` ghcr.io/metaform/jad/clearglass ` ) that acts as the authentication and
473+ authorization enforcement point for all protected APIs. Traefik's ` ForwardAuth ` mechanism intercepts every inbound
474+ request and calls ` clearglass ` 's ` /validate ` endpoint before forwarding it to the backend.
475+
476+ The proxy performs two checks:
477+
478+ 1 . ** Token validation** — it calls Keycloak's RFC 7662 token introspection endpoint
479+ (` /realms/edcv/protocol/openid-connect/token/introspect ` ) using its own client credentials (` clearglass ` /
480+ ` clearglass-secret ` ) to verify that the Bearer token in the ` Authorization ` header is active.
481+ 2 . ** Scope check** — the required OAuth2 scopes are passed as ` ?scope= ` query parameters by each Traefik middleware.
482+ The proxy checks that the token carries at least those scopes. If either check fails, the request is rejected with
483+ ` 401 Unauthorized ` before it ever reaches the backend service.
484+
485+ This design keeps authentication logic out of the individual services and centralizes it in one place, making it easy
486+ to add or modify access rules by updating the middleware definitions in
487+ [ ` k8s/base/jwt-middleware.yaml ` ] ( k8s/base/jwt-middleware.yaml ) .
488+
402489## Deploying JAD on a bare-metal/cloud-hosted Kubernetes
403490
404491KinD is geared towards local development and testing. For example, it comes with a bunch of useful defaults, such as
0 commit comments