Skip to main content
Version: 2026.07

API Gateway

The API Gateway is a reverse proxy that exposes several platform services through one external hostname. Instead of separate hostnames per service (registry.<customer_istari_fqdn>, and — once you add the Identity Service — an equivalent for it), clients reach both through a single API host at path prefixes: /registry and /identity. The proxy matches a prefix, strips it, and forwards the request to the matching in-cluster service; a path under no known prefix gets 404.

This page covers the three supported configurations for a cluster running no service mesh, the common case. Every service in the chart — the registry service, the frontend, the Identity Service, MCP, and the API Gateway itself — renders a Kubernetes Ingress and an Istio VirtualService, gated by independent values. Ingress is not a fallback for clusters without Istio: it is the fully supported path, and every example on this page uses it. If you do run Istio, substitute the matching virtualService.* values for the ingress.* values shown below; the chart's values.yaml documents them in the same shape.

Two chart values gate the whole surface, and neither implies the other:

ValueEffect
apiGateway.enabledDeploys the API Gateway itself: its Deployment, Service, and (per your values) Ingress or VirtualService.
apiGateway.apiUrlThe API Gateway's public base URL, e.g. https://api.<customer_istari_fqdn>. Setting it turns on the environment-variable contract described below for the registry service, the frontend, MCP, and (once deployed) the Identity Service. Deploying the API Gateway with apiUrl unset still deploys a working proxy — nothing points at it yet.

Deploying the Identity Service follows the same split, one level down:

ValueEffect
identity.enabledDeploys the Identity Service itself.
identity.clientIntegration.enabledMoves the registry service, the frontend, and MCP onto the Identity Service as their authentication authority.

Both default to false, and the chart never derives one from the other — even in a release that sets identity.enabled: true, identity.clientIntegration.enabled stays false until you also set it. Moving clients over needs both values. Setting only identity.enabled deploys a working Identity Service that nothing yet authenticates against; setting only identity.clientIntegration.enabled is refused outright (see below).

The gateway and the identity toggle interact in one place worth understanding before you touch either: the chart emits the identity-enabled environment variable to the registry service, the frontend, and MCP together, and only when identity.clientIntegration.enabled is true and apiGateway.apiUrl resolves to a value — never from apiGateway.apiUrl alone. This is not an arbitrary gate. The chart's own validation fails the Helm render if identity.clientIntegration.enabled is true while no gateway URL resolves, and independently of that guard, the registry service, the frontend, and MCP each treat identity-enabled-without-a-gateway-URL as a fatal error — at startup for the registry service and MCP, at config load for the frontend. There is no supported path that half-applies this change.

Finally: MCP is a client of the gateway, not a service it serves. It reaches the registry service through <base>/registry the same way the frontend does, and stays reachable at its own hostname (mcp.<customer_istari_fqdn>, per Istari Platform Installation) — the API Gateway has no /mcp prefix. https://api.<customer_istari_fqdn>/mcp returning 404 is correct behavior, not a misconfigured route.

Configuration 1: Neither Enabled

The baseline. No prerequisites beyond your existing installation, and no values to set — apiGateway.enabled: false and identity.enabled: false are already the chart defaults. Upgrading to chart version 5.0.0 with an otherwise unchanged values file is a version bump and nothing else: no new resources render, no environment variables change, and every existing hostname keeps working exactly as before.

Order of operations: helm upgrade to chart version 5.0.0.

Verification: kubectl get pods shows no new workloads (no api-gateway or identity pods); the registry service and frontend continue answering at their existing hostnames.

Rollback: helm rollback <release> <previous-revision>.

Reference: example_values/01-baseline-no-router-no-identity.yaml.

Configuration 2: Gateway Only

Adds the API Gateway in front of the registry service, with authentication unchanged. Clients reach the registry service through <api-host>/registry instead of registry.<customer_istari_fqdn> directly; they still authenticate against Zitadel exactly as before. The API Gateway and the Identity Service are independent — this configuration does not require the Identity Service, and deploying it does not enable the Identity Service.

Prerequisites

  • An Ingress controller (nginx, ALB/EKS Auto Mode, GCE, Traefik, or similar) watching the IngressClass you plan to use. The examples below assume no service mesh; on Istio, substitute the matching virtualService.* values — see the note above.
  • A DNS record for your chosen API hostname (for example api.<customer_istari_fqdn>), pointed at the Ingress controller's load balancer — the same way you already route <customer_istari_fqdn> and registry.<customer_istari_fqdn>.
  • A TLS Secret for that hostname (kubectl create secret tls ..., or one issued by cert-manager). TLS terminates at the Ingress controller; the API Gateway itself serves plain HTTP behind it.

Values to set

istari-values.yaml (excerpt)
apiGateway:
enabled: true
apiUrl: "https://api.<customer_istari_fqdn>"
ingress:
enabled: true
className: "nginx" # match your controller's IngressClass
hosts:
- host: api.<customer_istari_fqdn>
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- api.<customer_istari_fqdn>
secretName: api-<customer_istari_fqdn>-tls

apiGateway.apiUrl is what turns on the environment-variable contract — the chart never derives it from apiGateway.ingress, so a release with the Ingress configured but apiUrl left empty deploys a working API Gateway that nothing points at.

Order of operations

  1. Create the TLS Secret and DNS record for the API hostname.

  2. Set the values above and run helm upgrade.

  3. Restart the registry service and frontend Deployments. Neither carries a config-checksum annotation, so a helm upgrade that changes only apiGateway.apiUrl does not roll them on its own — they keep running with the old environment until you restart them explicitly:

    kubectl rollout restart deployment/istari-fileservice deployment/istari-frontend
    kubectl rollout status deployment/istari-fileservice deployment/istari-frontend

    (Add deployment/istari-mcp to both commands if MCP is deployed.)

Verification

curl -fsS https://api.<customer_istari_fqdn>/registry/api/v2/health/readiness

should return 200. Confirm the frontend still logs in exactly as before — this configuration changes only where registry traffic travels, not how anyone authenticates. https://api.<customer_istari_fqdn>/identity returns 502 until the Identity Service is deployed (Configuration 3) — the route always exists, but nothing backs it yet; that is expected, not an API Gateway misconfiguration.

Rollback

Set apiGateway.apiUrl: "" (or apiGateway.enabled: false to remove the API Gateway entirely), helm upgrade, then restart the same Deployments as above. Clearing apiGateway.apiUrl drops the chart's ConfigMap, and the direct endpoints your Secrets already carry (VITE_FS_URL, etc.) apply again — no data to restore.

If you set VITE_ISTARI_DIGITAL_API_URL in the frontend Secret yourself — or ISTARI_DIGITAL_API_URL in the registry Secret — remove that key and re-apply the Secret as part of the rollback. The chart lists its own ConfigMap first in each Deployment's envFrom, so a key you set in your Secret overrides the chart's value rather than the reverse. Clearing apiGateway.apiUrl therefore removes only the chart's copy; a Secret that still carries the key keeps pointing at a gateway you have just torn down.

Reference: example_values/02-router-only.yaml.

Configuration 3: Gateway and Identity

Adds the Identity Service behind the same gateway and moves the registry service, the frontend, and MCP onto it. This configuration only covers what the gateway changes — read Identity Service: Install and Configure for deploying the Identity Service itself and generating every credential it needs, and Identity Service: Registering Clients for registering the registry service, the frontend, and MCP with it (manually, or through the chart's identity.registryClientRegistration, identity.publicClientRegistration, and identity.agentRegistration hooks, which that page also covers). This page does not restate either.

Prerequisites

  • Configuration 2 already applied (or applied in the same release): the API Gateway deployed with apiGateway.apiUrl set.
  • The Identity Service installed and configured per Install and Configure, including its Secret (identity.secretName) populated with the signing key, database URL, and Zitadel credentials.
  • The registry service (and any other clients you intend to switch) registered with the Identity Service per Registering Clients.

Values to set

istari-values.yaml (excerpt)
apiGateway:
enabled: true
apiUrl: "https://api.<customer_istari_fqdn>"
ingress:
# ... same as Configuration 2
identity:
enabled: true
clientIntegration:
enabled: true
secretName: "istari-identity-service"

With apiGateway.apiUrl already resolved, this pair of values is what actually moves clients over — everything else in this configuration (the Identity Service Deployment, its database migrations, its registration hooks) is covered by the two linked pages. Set both together: identity.clientIntegration.enabled with identity.enabled left false deploys nothing to authenticate against, and the reverse configuration (clientIntegration.enabled: true without a resolved apiGateway.apiUrl) fails the Helm render outright — see the shared warning above.

With the gateway in place, the Identity Service needs no Ingress or DNS entry of its own: the API Gateway already serves it at <api-host>/identity, exactly as Install and Configure describes. The chart also has the Identity Service accept RFC 7523 client assertions addressed to that gateway-prefixed audience (<api-host>/identity) in addition to its canonical issuer — automatic, and not something you configure.

Order of operations

  1. Complete Install and Configure through its Step 5 (verify the Identity Service directly) with identity.enabled: true but identity.clientIntegration.enabled still false. Verifying the Identity Service on its own, before any client depends on it, isolates failures to one side of the switch.

  2. Complete Registering Clients for every client you plan to switch over.

  3. Set identity.clientIntegration.enabled: true and run helm upgrade.

  4. Restart the registry service, frontend, and (if deployed) MCP Deployments — the same restart caveat as Configuration 2 applies to this toggle as well:

    kubectl rollout restart deployment/istari-fileservice deployment/istari-frontend deployment/istari-mcp
    kubectl rollout status deployment/istari-fileservice deployment/istari-frontend deployment/istari-mcp

Verification

Follow Registering Clients: Verify a Registration for a token-level check, then confirm the frontend login flow end to end (it now drives the full /oauth2/authorize → Zitadel → /callback round trip through the gateway). Confirm https://api.<customer_istari_fqdn>/mcp still returns 404 — MCP consumes the gateway to reach the registry service and the Identity Service, but the API Gateway never serves MCP itself, so this is expected.

Rollback

Two independent steps, matching the two toggles:

  • Move clients back off the Identity Service, keeping it deployed: set identity.clientIntegration.enabled: false, helm upgrade, restart the same Deployments as above. The registry service, the frontend, and MCP fall back to Zitadel directly — their Zitadel configuration was never removed, only superseded while the toggle was on. Nothing in the Identity Service's database (tenants, registered clients) is affected, so re-enabling later needs no re-registration.
  • Remove the Identity Service entirely: additionally set identity.enabled: false.

Reference: example_values/03-router-and-identity.yaml.