Skip to content

kastoria-proxy-mtls

An NGINX reverse proxy that serves as an internal Kastoria ingress with support for mutual TLS (mTLS). The ingress serves hosts inside the Azure VNet, where requests arrive over HTTP with the client certificate provided in the X-Forwarded-Client-Cert header. Each route is gated by the client certificate's SHA-256 thumbprint found in the client certificate's HASH= value. The ingress listens on port 8080 and routes to the same upstreams as the public proxy.

The public variant is a separate image, kastoria-proxy.

Runtime details

Property Value
Runtime base image nginxinc/nginx-unprivileged:1.31-alpine (pinned by digest)
Exposed port 8080
Container user nginx (non-root)
Entrypoint /entrypoint.sh (validates the role allowlist, renders the role maps and config, then execs NGINX)
Command CMD ["nginx", "-g", "daemon off;"]
Health check GET http://localhost:8080/healthz (every 30s, 5s timeout, 30s start period, 3 retries)
Stop signal SIGTERM

Both Azure proxy variants build from a common config template. The mTLS build keeps the mutual-TLS authorization blocks verbatim, so the shipped config proves its mTLS posture.

Enabling mTLS Authentication

To get mTLS working, the following is required:

  1. TLS termination occurs at the Azure Container Apps Environment's Envoy-based ingress.
  2. The calling clients' CA certificate must be registered with the environment (which will allow Envoy to validate the client requests).
  3. The kastoria-proxy-mtls container app's ingress must be configured with clientCertificateMode: require, which ensures the client certificate exists and is forwarded to the proxy.
  4. The KASTORIA_MTLS_CLIENT_ROLES environment variable (see below) defining the mTLS routing rules must exist and be formatted correctly.

OCI labels

Label Value
org.opencontainers.image.title Kastoria Reverse Proxy
org.opencontainers.image.description NGINX reverse proxy for the Kastoria Health platform
org.opencontainers.image.licenses Proprietary
org.opencontainers.image.url https://github.com/merkalis-io/kastoria-health
org.opencontainers.image.documentation https://github.com/merkalis-io/kastoria-health
io.kastoria.health-endpoint /

The org.opencontainers.image.version, org.opencontainers.image.revision, org.opencontainers.image.created, org.opencontainers.image.source, io.kastoria.base-image, and io.kastoria.service labels are injected at build time by the CI/CD pipeline.

Pull and verify

Promoted images are published to the Distribution Registry under the customer namespace:

docker pull acrmerkalisdist0c66.azurecr.io/<customer>/kastoria-proxy-mtls:<release-tag>
notation verify acrmerkalisdist0c66.azurecr.io/<customer>/kastoria-proxy-mtls:<release-tag>

See the Distribution Registry guide for authentication and trust setup.

Environment variables

Variable Secret Required Default Description
KASTORIA_MTLS_CLIENT_ROLES[1] Yes Yes — mTLS routing rules. Startup fails if missing, empty, or malformed.
KASTORIA_HEALTH_ADDRESS[2] No No kastoria-health:3000 Upstream DICOMweb server host and port.
KASTORIA_SMARTLAUNCH_ADDRESS[2] No No kastoria-smartlaunch:4000 Upstream SMART Launch API host and port.
KASTORIA_CONSOLEAPI_ADDRESS[2] No No kastoria-consoleapi:3005 Upstream Admin Console API host and port.
KASTORIA_CONSOLEUI_ADDRESS[2] No No kastoria-consoleui:8081 Upstream Admin Console UI host and port.
KASTORIA_REPORTVIEW_ADDRESS[2] No No kastoria-perfview:80 Upstream report viewer host and port.
KASTORIA_REPORTVIEW_ENABLED No No true Set to false to strip the /reportview/ route.
OHIF_VIEWER_ADDRESS[2] No No kastoria-ohif:8080 Upstream OHIF viewer host and port.
PORT[3] No No 8080 Used by the container HEALTHCHECK; NGINX listens on 8080.

Every variable above is substituted into the NGINX config at container start by /entrypoint.sh, which also validates the mTLS routing rules and renders the role maps; disabled route blocks are removed before NGINX starts.

Note: The default values listed for the various *_ADDRESS are in place for using the non-mTLS proxy in a local docker compose environment. When deploying to Azure you must change these (see [2] below), or the container will fail to start.

mTLS Routing Rules

The mTLS routing rule is provided in the KASTORIA_MTLS_CLIENT_ROLES environment variable. It is a routing allowlist that maps each client certificate to its roles in the following format:

Thumbprint→role allowlist, <sha256hex>:role1,role2;<sha256hex>:role3;....

Thumbprint is the SHA-256 hash of the client's certificate as a hex string. role is defined in the following way:

Role Grants
dicomweb /studies, /errors
smart /smart/
console /api/, /console/
reportview /reportview/
ohif / (catch-all)
all every route

Note: The proxy's /healthz endpoint is exempt from the mTLS checks.

Deploying to an Azure Container Apps Environment

[1] The role allowlist should be supplied via a secretref: to a Key Vault secret. To allow automatic updates, this should be a versionless secret. The value of KASTORIA_MTLS_CLIENT_ROLES is validated at startup. a) Thumbprints must be exactly 64 hex characters, b) No whitespace or newlines are allowed, and c) There must be no empty or duplicate entries.

[2] The various *_ADDRESS variables should be set to the environment's internal FQDN for the container app. The Azure configuration template automatically includes the correct (443) port.

[3] The selected value for PORT must match the environment's ingress Target port for the container app.

Available versions

  • v0.10.0
  • v0.9.1 — deprecated for security reasons (CVE-2026-93990); use v0.10.0