API gateway
Install the API gateway once per OpenLM Platform installation, in the same namespace, before OpenLM Platform itself. The OpenLM web UIs get their data from https://<your address>/api/..., and the API gateway receives every one of these requests and forwards it to the OpenLM Platform service that handles it.
The installation at a glance:
- What: A Helm chart,
openlm/openlm-apigateway, based on Tyk Gateway (open source). - You provide: A Redis, a storage class, and a secret.
- You run: Two
kubectlcommands, one values file, and onehelmcommand, in about 10 minutes. - You check: The gateway pod runs, its job says
Bootstrap completed successfully, and the routes are listed. - Fixed rule: The Helm release is always called
openlm-gateway.
How it works
Each request to /api takes these steps:
- Your Ingress (or OpenShift Route) sends every path that starts with
/apito the gateway. - The gateway looks up the route for the path. Each route maps one path, such as
/api/licenses, to one OpenLM Platform service in the same namespace, such asopenlm-licenses. - The gateway forwards the request and returns the answer. It doesn't check sign-in itself. The OpenLM Platform services do.
The routes come with the chart. After every installation and upgrade, a short bootstrapper job loads the routes for that chart version into the gateway. The gateway keeps them on a volume, so they survive a restart. It keeps its working data in Redis.
Details for operators
The gateway is made of these parts:
- Gateway: Tyk Gateway 5.9.1 (open source), one Deployment,
gateway-openlm-gateway-tyk-gateway. It listens on port 8080 for traffic and on a separate port 9699 for its control API. The control API has its own Service and is never exposed outside the cluster. - Routes: Keyless Tyk API definitions with
listen_path/api/<service>and a target of the formhttp://openlm-<service>/..., a short Service name. That is why the gateway must run in the platform's namespace. - Bootstrapper job:
gateway-bootstrapper-job-<revision>. It waits until/helloon the control API reports healthy, deletes all API definitions, creates the ones bundled in its image, reloads the gateway and checks health again. It retries for about 5 minutes, with at most 3 attempts, and removes itself 5 minutes after it finishes. - State: API definitions are files on the volume
tyk-app-claim. Policies and middleware have their own volumes. Each volume is 200 MB,ReadWriteOnce, and is kept when you uninstall. Redis holds the gateway's runtime data. - Secret:
APISecretprotects the control API. The gateway and the bootstrapper read it from the same Secret.
Before you begin
Confirm these prerequisites:
- The namespace of OpenLM Platform exists. The examples use
openlm. Any name works, as long as the gateway and OpenLM Platform share it. - A Redis that the namespace can reach: its host, port, password, and whether it uses TLS. See Redis.
- A storage class that provides
ReadWriteOncevolumes:kubectl get storageclass. - Helm 3 or 4, and
kubectl(oroc) access to the namespace. - You know how
/apireaches the gateway in your setup. Usually the OpenLM Platform Ingress does it, or an OpenShift Route. See Expose /api.
Install the API gateway
Follow these steps in order.
1. Add the OpenLM Helm repository
Set the namespace, add the repository, and list the latest API gateway release:
export NS=openlm
helm repo add openlm https://openlm-helm.github.io/helmcharts
helm repo update openlm
helm search repo openlm/openlm-apigateway --devel
--develHelm ignores pre-release versions such as 1.0.0-rc.2 unless you add --devel. The commands on this page use --devel, so they always install the latest API gateway release, the one that goes with every OpenLM Platform release.
If this machine has no internet access, run helm pull openlm/openlm-apigateway --devel on a machine that has it. It may print unable to find exact version requested; falling back to closest available version, which is harmless. Copy the .tgz file over, and use the file in place of openlm/openlm-apigateway in the following steps.
2. Create the secrets
Create one Secret for the control API and one for the Redis password:
kubectl -n "$NS" create secret generic openlm-gateway-secrets \
--from-literal=APISecret="$(openssl rand -hex 32)"
kubectl -n "$NS" create secret generic openlm-gateway-redis \
--from-literal=password='<your Redis password or access key>'
APISecret protects the gateway's control API. The chart has no default and stops with a message if you don't provide one. If your Redis has no password, skip the second command and leave out passSecret in the next step.
3. Write the values file
Write the values file for the standard setup, where the OpenLM Platform Ingress sends /api to the gateway and Redis uses TLS:
# gateway-values.yaml
storageClassName: <your storage class>
tyk-oss:
global:
secrets:
useSecretName: openlm-gateway-secrets # the Secret from step 2
redis:
addrs: ["<redis host>:<port>"]
useSSL: true # false for a Redis without TLS
passSecret: { name: openlm-gateway-redis, keyName: password }
storage: { database: 0 }
tyk-gateway:
gateway:
hostName: <your address>
ingress: { enabled: false } # /api comes through the platform's Ingress
On OpenShift, add the Route instead, as described in Expose /api.
4. Install
Install the chart:
helm upgrade --install openlm-gateway openlm/openlm-apigateway --devel \
-n "$NS" -f gateway-values.yaml --wait --timeout 10m
The release name must be openlm-gateway. OpenLM Platform sends /api to the Service gateway-svc-openlm-gateway-tyk-gateway, and that name comes from the release name.
5. Check
Check the gateway pod and the bootstrapper job:
kubectl -n "$NS" get pods | grep -E "gateway"
kubectl -n "$NS" logs -l job-name --tail=200 | grep -E "Bootstrap completed|failed|Error"
The output shows the following:
- The gateway pod
gateway-openlm-gateway-tyk-gateway-…with1/1andRunning. - A pod
gateway-bootstrapper-job-…withCompleted, and the log lineBootstrap completed successfully.
The job removes itself 5 minutes after it finishes. To check the routes at any time, see Check the routes.
Check the routes
Check the routes after an installation or upgrade, or when a page in the web UI shows no data. The routes are in place when the gateway lists one for every OpenLM service.
To list the routes, open a tunnel to the gateway's control API and query it:
# 1. Open a tunnel to the gateway's control API (leave it running, use a second terminal)
kubectl -n "$NS" port-forward svc/gateway-control-svc-openlm-gateway-tyk-gateway 9699:9699
# 2. Read the secret and ask the gateway
export TYK_SECRET="$(kubectl -n "$NS" get secret openlm-gateway-secrets -o jsonpath='{.data.APISecret}' | base64 -d)"
curl -s localhost:9699/hello # health: "status":"pass"
curl -s -H "x-tyk-authorization: $TYK_SECRET" localhost:9699/tyk/apis \
| jq -r '.[] | [.proxy.listen_path, .proxy.target_url] | @tsv' | sort
In the output, check the following:
/helloreports"status":"pass", with Redispass.- The list has one line per route: the path first, then the service. Version 1.0.0-rc.2 loads 80 routes. Check that the path a failing page calls is in the list.
- If the list is empty or a path is missing, the bootstrapper job didn't finish. Run the upgrade command from Upgrade again with the same version. Each run starts a new job that reloads all routes.
If you don't have jq, leave out the last line and search the output for "listen_path".
To check the whole way from outside, sign in to the web UI and open a few pages. Each page loads its data through /api.
Expose /api
To send /api to the gateway, use exactly one of these setups:
| Setup | When | What to set |
|---|---|---|
| Platform Ingress (standard) | Kubernetes with the platform's single Ingress | tyk-oss.tyk-gateway.gateway.ingress.enabled: false. Nothing else: the platform's Ingress already sends /api to the gateway. |
| OpenShift Route | OpenShift, ROSA, ARO | openShiftRoute.enabled: true, openShiftRoute.host: <your address>, and the Tyk Ingress off |
| Gateway Ingress | The gateway without the platform's Ingress | The Tyk Ingress on, with your host, class and TLS secret |
With chart defaults, the gateway creates an Ingress for the placeholder host gateway-domain.com. Set tyk-oss.tyk-gateway.gateway.ingress.enabled: false unless you use it.
OpenShift Route
To create the Route, add these settings to your values file:
openShiftRoute:
enabled: true
host: <your address>
tyk-oss:
tyk-gateway:
gateway:
ingress: { enabled: false }
The chart creates the Route openlm-gateway in the release namespace: path /api, TLS ends at the router (edge), HTTP is redirected to HTTPS, and timeouts are 600 seconds. It sets the same security headers as the OpenLM Platform Routes: HSTS (one year, including subdomains), X-Frame-Options: SAMEORIGIN, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, and Content-Security-Policy: frame-ancestors 'self'. The headers need OpenShift 4.14 or higher. On older versions, set openShiftRoute.routeSecurity.enabled: false.
To check the Route, run oc -n "$NS" get route openlm-gateway. If you created an /api Route by hand earlier, delete it. With two Routes for the same host and path, OpenShift uses the older one.
Gateway Ingress
To turn on the gateway's own Ingress, add these settings with your host, class, and TLS secret:
tyk-oss:
tyk-gateway:
gateway:
hostName: <your address>
ingress:
enabled: true
className: <your ingress class>
hosts:
- host: <your address>
paths: [{ path: /api, pathType: ImplementationSpecific }]
tls:
- secretName: <your TLS secret>
hosts: [<your address>]
The chart sets annotations for ingress-nginx (100 MB request body, 600-second timeouts). If you use another controller, replace annotations with its equivalents.
Redis
Set addrs, useSSL, and storage.database for your Redis:
| Your Redis | addrs | useSSL | storage.database |
|---|---|---|---|
| In your network, no TLS | ["<host>:6379"] | false | a free database, for example 2 |
| With TLS | ["<host>:<TLS port>"] | true | a free database |
| Azure Managed Redis | ["<name>.<region>.redis.azure.net:10000"] | true | 0 |
| Azure Cache for Redis | ["<name>.redis.cache.windows.net:6380"] | true | a free database |
Keep these points in mind:
- Azure Managed Redis: create it with the non-clustered policy. It has one database, so
storage.databaseis0. - The gateway can share a Redis with OpenLM Platform. Give it its own database number where the Redis has several.
- If your Redis certificate comes from a private CA, contact OpenLM support. For a test installation only,
tyk-oss.global.redis.sslInsecureSkipVerify: trueskips the certificate check.
Settings reference
Set these settings in your values file. All Tyk settings sit under tyk-oss:, and any setting you don't set keeps its default:
| Setting | Default | What it does |
|---|---|---|
storageClassName | (none, required) | Storage class for the three volumes |
tyk-oss.global.secrets.useSecretName | (empty) | Your Secret with the key APISecret. One of the two secret settings is required. |
tyk-oss.global.secrets.APISecret | (empty) | Plain-text alternative to useSecretName |
tyk-oss.global.redis.addrs | ["openlm-redis.openlm:6379"] | Redis host:port |
tyk-oss.global.redis.useSSL | false | TLS to Redis |
tyk-oss.global.redis.passSecret.name, .keyName | (empty) | Secret and key with the Redis password |
tyk-oss.global.redis.storage.database | 2 | Redis database number |
tyk-oss.tyk-gateway.gateway.hostName | gateway-domain.com | Your address |
tyk-oss.tyk-gateway.gateway.ingress.enabled | true | The gateway's own Ingress |
tyk-oss.tyk-gateway.gateway.replicaCount | 1 | Number of gateway pods. More than one gives you no downtime during upgrades. |
tyk-oss.tyk-gateway.gateway.resources | (none) | CPU and memory requests and limits |
tyk-oss.tyk-gateway.gateway.nodeSelector, .tolerations, .affinity | (none) | Where the gateway pods run |
tyk-oss.tyk-gateway.gateway.log.level | warn | debug, info, warn or error |
tyk-oss.tyk-gateway.gateway.extraEnvs | 600-second timeouts | Extra Tyk settings as TYK_GW_* variables. Replacing the list removes the timeouts: copy them in. |
openShiftRoute.enabled | false | Create the OpenShift Route for /api |
openShiftRoute.host | (empty) | Your address. Required when the Route is on. |
openShiftRoute.name | openlm-gateway | Name of the Route, for example to take over an existing one |
openShiftRoute.routeSecurity.enabled | true | HSTS and security headers on the Route |
openShiftRoute.routeSecurity.hstsMaxAge | 31536000 | HSTS max-age, in seconds |
openShiftRoute.routeSecurity.hstsIncludeSubDomains | true | HSTS includeSubDomains |
bootstrapperJob.image | public.ecr.aws/r3q3q2f4/olm-gateway-bootstrapper:<version> | Image with the routes. Each chart version pins its own. |
bootstrapperJob.affinity, .tolerations | (none) | Where the job runs. The job has no nodeSelector setting: use affinity. |
bootstrapperJob.argocd.enabled | false | true when Argo CD deploys the chart: the job then runs as a PostSync hook and the application stays in sync |
Private registry (air-gapped)
Mirror these images and point the chart at your copies:
| Image | Setting |
|---|---|
docker.tyk.io/tyk-gateway/tyk-gateway:v5.9.1 | tyk-oss.tyk-gateway.gateway.image.repository and .tag |
busybox:1.32 | tyk-oss.tyk-gateway.gateway.initContainers.setupDirectories.repository |
public.ecr.aws/r3q3q2f4/olm-gateway-bootstrapper:<version> | bootstrapperJob.image (full reference) |
Set tyk-oss.tyk-gateway.gateway.imagePullSecrets for the gateway. The bootstrapper job runs with the namespace's default service account: add your pull secret to that service account. helm test uses zalbiraw/alpine-curl-jq, and only when you run helm test.
Upgrade
Read the release notes of the new version first. Then upgrade the release:
helm -n "$NS" get values openlm-gateway > gateway-values.yaml # only if you no longer have the file
helm repo update openlm
helm upgrade openlm-gateway openlm/openlm-apigateway --devel \
-n "$NS" -f gateway-values.yaml --wait --timeout 10m
Each upgrade runs the bootstrapper job again, which replaces all routes with the ones of the new version. After the upgrade, check the routes.
Upgrade from openlm-gateway 0.2.x
Up to 0.2.x, the chart was called openlm-gateway and came as a file. Upgrade the same release with the new chart, and keep the release name openlm-gateway.
First, check whether your installation has its own secret:
helm -n "$NS" get values openlm-gateway | grep -E "useSecretName|APISecret"
- If it shows
useSecretName, or anAPISecretyou chose yourself, upgrade with the command in Upgrade. No objects change and the gateway isn't restarted. - If it shows nothing, or an
APISecretyou didn't choose, you need your own secret. Create the Secret from Install, step 2, adduseSecretName: openlm-gateway-secretsto your values file, then upgrade. The gateway restarts once, so/apiis unavailable for a few seconds. Plan a short maintenance window, and update any script of your own that calls the control API with the old secret.
If the upgrade stops with "The gateway needs its own APISecret", nothing has changed in the cluster. Create the Secret and run it again.
Don't install the new chart under a new release name. That creates a second gateway with other Service names, and /api keeps going to the old one.
Operate
Rotate the secrets, read the logs, or uninstall the gateway.
Rotate the secrets
The gateway reads both secrets when it starts, so restart it after a change:
kubectl -n "$NS" create secret generic openlm-gateway-secrets \
--from-literal=APISecret="$(openssl rand -hex 32)" --dry-run=client -o yaml | kubectl -n "$NS" apply -f -
kubectl -n "$NS" rollout restart deployment gateway-openlm-gateway-tyk-gateway
Rotate the Redis password the same way with openlm-gateway-redis: change it in Redis, update the Secret, restart. The gateway can't reach Redis between the first and the last step.
Read the logs
To read the gateway's logs, run kubectl -n "$NS" logs deploy/gateway-openlm-gateway-tyk-gateway. For more detail, set tyk-oss.tyk-gateway.gateway.log.level: debug and upgrade. Set it back afterward.
Uninstall
Uninstall the release. Delete the volumes only if you want to remove them as well:
helm -n "$NS" uninstall openlm-gateway
kubectl -n "$NS" delete pvc tyk-app-claim tyk-policies-claim tyk-middleware-claim # only to remove the volumes as well
The volumes and your two Secrets stay unless you delete them.
Troubleshooting
If the gateway doesn't work, find what you see in this table:
| What you see | Likely cause | What to do |
|---|---|---|
helm stops: The gateway needs its own APISecret | No secret set, or the one shipped with 0.2.x | Install, step 2, then set useSecretName |
helm stops: Please define storageClassName to be used (before 1.0.0-rc.2: Pelase define…) | storageClassName missing | Set it to one of kubectl get storageclass |
Pods wait in Pending, volumes Pending | The storage class can't provide ReadWriteOnce volumes | Use another storage class |
Gateway pod restarts, log mentions redis | Wrong host, port, password, or TLS setting | Check addrs, useSSL and the Secret openlm-gateway-redis. Azure: port 10000 or 6380, TLS on |
Log or job mentions CROSSSLOT | Azure Managed Redis with a clustered policy | Recreate the cache with the non-clustered policy |
| Bootstrapper job fails after about 5 minutes | Gateway not healthy, usually Redis | Fix the gateway first, then run the upgrade again |
Web UI loads, but pages show no data, and /api/... returns 404 | Routes not loaded | Check the routes, then run the upgrade again |
/api/<service> returns 502 or 503 | That service isn't running, or the gateway is in another namespace than the platform | Run kubectl -n "$NS" get pods, and install the gateway in the platform's namespace |
OpenShift: /api/... shows the home page | No Route for /api | Set openShiftRoute.enabled: true, or check oc get route |
| Two gateways after an upgrade | The new chart was installed under a new release name | Uninstall the new release, and upgrade openlm-gateway instead |
Technical reference
Objects the chart creates
The chart creates these objects:
| Kind | Name | Notes |
|---|---|---|
| Deployment | gateway-openlm-gateway-tyk-gateway | Tyk Gateway 5.9.1, init container busybox prepares the directories. Runs as non-root with a read-only root file system. |
| Service | gateway-svc-openlm-gateway-tyk-gateway | Port 8080, traffic. The platform's Ingress and the Route point here. |
| Service | gateway-control-svc-openlm-gateway-tyk-gateway | Port 9699, control API. Inside the cluster only. |
| Job | gateway-bootstrapper-job-<revision> | Loads the routes. Removed 5 minutes after it finishes. |
| PersistentVolumeClaim | tyk-app-claim, tyk-policies-claim, tyk-middleware-claim | 200 MB each, ReadWriteOnce, kept on uninstall |
| Secret | secrets-openlm-gateway-tyk-gateway | Created by the chart for values you set in plain text (APISecret, Redis password). Not needed when you use useSecretName and passSecret. |
| Secret | tyk-operator-conf | May be created for Tyk tooling. Holds no secret values when you use useSecretName. |
| Ingress | openlm-gateway-tyk-gateway | Only with ingress.enabled: true |
| Route | openlm-gateway (or openShiftRoute.name) | Only with openShiftRoute.enabled: true |
Security notes
Keep these security points in mind:
- The control API (port 9699) can change every route. Keep it inside the cluster: no Ingress, Route or
LoadBalancerforgateway-control-svc-…. If you use NetworkPolicies, allow port 9699 only from the bootstrapper job's pods. APISecretis the key to the control API. Keep it in a Secret (useSecretName) rather than in your values file, and rotate it as in Operate.- The routes are keyless: the gateway forwards requests without checking sign-in, and each platform service checks the user's token itself.
- On OpenShift, the Route adds HSTS and the security headers listed in Expose /api.
The documentation team might draft this page using a large language model. A technical writer reviews every page and verifies it against the product before publishing it. A human makes the final decision.