Skip to main content

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.

In short

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 kubectl commands, one values file, and one helm command, 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:

  1. Your Ingress (or OpenShift Route) sends every path that starts with /api to the gateway.
  2. 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 as openlm-licenses.
  3. 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 form http://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 /hello on 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: APISecret protects 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 ReadWriteOnce volumes: kubectl get storageclass.
  • Helm 3 or 4, and kubectl (or oc) access to the namespace.
  • You know how /api reaches 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
Release candidates need --devel

Helm 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-… with 1/1 and Running.
  • A pod gateway-bootstrapper-job-… with Completed, and the log line Bootstrap 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:

  • /hello reports "status":"pass", with Redis pass.
  • 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:

SetupWhenWhat to set
Platform Ingress (standard)Kubernetes with the platform's single Ingresstyk-oss.tyk-gateway.gateway.ingress.enabled: false. Nothing else: the platform's Ingress already sends /api to the gateway.
OpenShift RouteOpenShift, ROSA, AROopenShiftRoute.enabled: true, openShiftRoute.host: <your address>, and the Tyk Ingress off
Gateway IngressThe gateway without the platform's IngressThe Tyk Ingress on, with your host, class and TLS secret
The gateway's own Ingress is on by default

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 RedisaddrsuseSSLstorage.database
In your network, no TLS["<host>:6379"]falsea free database, for example 2
With TLS["<host>:<TLS port>"]truea free database
Azure Managed Redis["<name>.<region>.redis.azure.net:10000"]true0
Azure Cache for Redis["<name>.redis.cache.windows.net:6380"]truea free database

Keep these points in mind:

  • Azure Managed Redis: create it with the non-clustered policy. It has one database, so storage.database is 0.
  • 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: true skips 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:

SettingDefaultWhat 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.useSSLfalseTLS to Redis
tyk-oss.global.redis.passSecret.name, .keyName(empty)Secret and key with the Redis password
tyk-oss.global.redis.storage.database2Redis database number
tyk-oss.tyk-gateway.gateway.hostNamegateway-domain.comYour address
tyk-oss.tyk-gateway.gateway.ingress.enabledtrueThe gateway's own Ingress
tyk-oss.tyk-gateway.gateway.replicaCount1Number 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.levelwarndebug, info, warn or error
tyk-oss.tyk-gateway.gateway.extraEnvs600-second timeoutsExtra Tyk settings as TYK_GW_* variables. Replacing the list removes the timeouts: copy them in.
openShiftRoute.enabledfalseCreate the OpenShift Route for /api
openShiftRoute.host(empty)Your address. Required when the Route is on.
openShiftRoute.nameopenlm-gatewayName of the Route, for example to take over an existing one
openShiftRoute.routeSecurity.enabledtrueHSTS and security headers on the Route
openShiftRoute.routeSecurity.hstsMaxAge31536000HSTS max-age, in seconds
openShiftRoute.routeSecurity.hstsIncludeSubDomainstrueHSTS includeSubDomains
bootstrapperJob.imagepublic.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.enabledfalsetrue 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:

ImageSetting
docker.tyk.io/tyk-gateway/tyk-gateway:v5.9.1tyk-oss.tyk-gateway.gateway.image.repository and .tag
busybox:1.32tyk-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 an APISecret you chose yourself, upgrade with the command in Upgrade. No objects change and the gateway isn't restarted.
  • If it shows nothing, or an APISecret you didn't choose, you need your own secret. Create the Secret from Install, step 2, add useSecretName: openlm-gateway-secrets to your values file, then upgrade. The gateway restarts once, so /api is 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 seeLikely causeWhat to do
helm stops: The gateway needs its own APISecretNo secret set, or the one shipped with 0.2.xInstall, step 2, then set useSecretName
helm stops: Please define storageClassName to be used (before 1.0.0-rc.2: Pelase define…)storageClassName missingSet it to one of kubectl get storageclass
Pods wait in Pending, volumes PendingThe storage class can't provide ReadWriteOnce volumesUse another storage class
Gateway pod restarts, log mentions redisWrong host, port, password, or TLS settingCheck addrs, useSSL and the Secret openlm-gateway-redis. Azure: port 10000 or 6380, TLS on
Log or job mentions CROSSSLOTAzure Managed Redis with a clustered policyRecreate the cache with the non-clustered policy
Bootstrapper job fails after about 5 minutesGateway not healthy, usually RedisFix the gateway first, then run the upgrade again
Web UI loads, but pages show no data, and /api/... returns 404Routes not loadedCheck the routes, then run the upgrade again
/api/<service> returns 502 or 503That service isn't running, or the gateway is in another namespace than the platformRun kubectl -n "$NS" get pods, and install the gateway in the platform's namespace
OpenShift: /api/... shows the home pageNo Route for /apiSet openShiftRoute.enabled: true, or check oc get route
Two gateways after an upgradeThe new chart was installed under a new release nameUninstall the new release, and upgrade openlm-gateway instead

Technical reference​

Objects the chart creates

The chart creates these objects:

KindNameNotes
Deploymentgateway-openlm-gateway-tyk-gatewayTyk Gateway 5.9.1, init container busybox prepares the directories. Runs as non-root with a read-only root file system.
Servicegateway-svc-openlm-gateway-tyk-gatewayPort 8080, traffic. The platform's Ingress and the Route point here.
Servicegateway-control-svc-openlm-gateway-tyk-gatewayPort 9699, control API. Inside the cluster only.
Jobgateway-bootstrapper-job-<revision>Loads the routes. Removed 5 minutes after it finishes.
PersistentVolumeClaimtyk-app-claim, tyk-policies-claim, tyk-middleware-claim200 MB each, ReadWriteOnce, kept on uninstall
Secretsecrets-openlm-gateway-tyk-gatewayCreated by the chart for values you set in plain text (APISecret, Redis password). Not needed when you use useSecretName and passSecret.
Secrettyk-operator-confMay be created for Tyk tooling. Holds no secret values when you use useSecretName.
Ingressopenlm-gateway-tyk-gatewayOnly with ingress.enabled: true
Routeopenlm-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 LoadBalancer for gateway-control-svc-…. If you use NetworkPolicies, allow port 9699 only from the bootstrapper job's pods.
  • APISecret is 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.