Skip to main content

Gateway Auto-Registration Guide

This guide explains how to configure and deploy STOA gateways with automatic registration to the Control Plane.

ADR Reference

This feature is defined in ADR-036: Gateway Auto-Registration.

Overview​

STOA gateways can automatically register with the Control Plane at startup, eliminating the need for manual registration via API calls. This provides an "Apple ecosystem" experience where gateways appear in the Console UI within seconds of deployment.

Key benefits:

  • Zero-config deployment (2 environment variables)
  • Automatic re-registration on restart
  • Real-time health visibility via heartbeat
  • Self-healing (gateway recovery is automatic)

Architecture​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Control Plane API β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Gateway Internal β”‚ β”‚ Gateway Health Worker β”‚ β”‚
β”‚ β”‚ /v1/internal/gateways β”‚ Marks stale gateways OFFLINE β”‚ β”‚
β”‚ β”‚ - /register β”‚ β”‚ (90s timeout) β”‚ β”‚
β”‚ β”‚ - /{id}/heartbeat β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ - /{id}/config β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”‚ HTTPS (X-Gateway-Key header)
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STOA Gateway β”‚ β”‚ STOA Sidecar β”‚
β”‚ (edge-mcp) β”‚ β”‚ + Kong/Envoy β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ 1. Register β”‚ β”‚ ext_authz β”‚
β”‚ 2. Heartbeat β”‚ β”‚ ↓ β”‚
β”‚ (30s) β”‚ β”‚ Policy/Meter β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quick Start​

Tier 1: STOA Native Gateway​

Deploy a STOA gateway with automatic registration:

# Minimal configuration (2 env vars)
export STOA_CONTROL_PLANE_URL=https://api.<YOUR_DOMAIN>
export STOA_CONTROL_PLANE_API_KEY=gw_your_key_here

# Start the gateway
./stoa-gateway

The gateway will:

  1. Derive identity from hostname + mode + environment
  2. Call POST /v1/internal/gateways/register
  3. Start heartbeat loop (every 30 seconds)
  4. Appear in Console UI at /gateways

Tier 2: Sidecar Mode​

Deploy STOA as a sidecar alongside a third-party gateway:

# Kubernetes deployment example
apiVersion: apps/v1
kind: Deployment
metadata:
name: kong-with-stoa-sidecar
spec:
template:
spec:
containers:
# Main gateway (Kong)
- name: kong
image: kong:3.5
env:
- name: KONG_PLUGINS
value: "ext-authz"
- name: KONG_EXT_AUTHZ_URL
value: "http://localhost:8081/authz"
ports:
- containerPort: 8000

# STOA sidecar
- name: stoa-sidecar
image: ghcr.io/stoa/stoa-gateway:latest
env:
- name: STOA_GATEWAY_MODE
value: "sidecar"
- name: STOA_CONTROL_PLANE_URL
value: "https://api.<YOUR_DOMAIN>"
- name: STOA_CONTROL_PLANE_API_KEY
valueFrom:
secretKeyRef:
name: stoa-sidecar-secrets
key: control-plane-api-key
ports:
- containerPort: 8081 # ext_authz endpoint

Control Plane Configuration​

1. Create Gateway API Keys​

Configure the Control Plane to accept gateway registrations:

# Create Kubernetes secret with API keys
kubectl create secret generic stoa-gateway-api-keys \
--namespace stoa-system \
--from-literal=GATEWAY_API_KEYS="gw_prod_key_abc123,gw_staging_key_xyz789"

Key format: Any string, but we recommend the format gw_{environment}_{random}.

Key rotation: Multiple keys are supported (comma-separated). Add a new key before removing the old one.

2. Deploy Control Plane with Keys​

Patch the Control Plane deployment:

kubectl patch deployment control-plane-api -n stoa-system \
--type='json' \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/env/-", "value": {"name": "GATEWAY_API_KEYS", "valueFrom": {"secretKeyRef": {"name": "stoa-gateway-api-keys", "key": "GATEWAY_API_KEYS"}}}}]'

Or via Helm:

# values.yaml
controlPlane:
env:
GATEWAY_API_KEYS:
secretKeyRef:
name: stoa-gateway-api-keys
key: GATEWAY_API_KEYS

Gateway Configuration Reference​

Environment Variables​

VariableRequiredDefaultDescription
STOA_CONTROL_PLANE_URLYes-Control Plane API URL
STOA_CONTROL_PLANE_API_KEYYes-Shared secret for authentication
STOA_GATEWAY_MODENoedge-mcpGateway mode: edge-mcp, sidecar, proxy, shadow
STOA_ENVIRONMENTNodevEnvironment identifier for grouping
STOA_TENANT_IDNo-Optional tenant restriction

Registration Payload​

The gateway sends this payload at startup:

{
"hostname": "stoa-gateway-7f8b9c",
"mode": "edge-mcp",
"version": "0.1.0",
"environment": "prod",
"capabilities": ["rest", "mcp", "sse", "oidc", "rate_limiting"],
"admin_url": "http://10.0.1.50:8080",
"tenant_id": null
}

Heartbeat Payload​

Every 30 seconds:

{
"uptime_seconds": 3600,
"routes_count": 15,
"policies_count": 5,
"requests_total": 10000,
"error_rate": 0.01
}

Identity Derivation​

Gateway identity is deterministic: {hostname}-{mode_normalized}-{environment}

HostnameModeEnvironmentDerived Name
stoa-gw-abc123edge-mcpprodstoa-gw-abc123-edgemcp-prod
kong-sidecar-xyzsidecarstagingkong-sidecar-xyz-sidecar-staging

This enables:

  • Idempotent registration: Same gateway restarts update rather than duplicate
  • Clear naming: Easy to identify in Console UI
  • Environment filtering: Group gateways by environment

Helm Chart Configuration​

STOA Gateway (Tier 1)​

The Helm chart manages the STOA_CONTROL_PLANE_API_KEY secret via a Vault-backed ExternalSecret:

# values.yaml
stoaGateway:
enabled: true
replicas: 2

# Control Plane connection
controlPlaneUrl: "http://control-plane-api.stoa-system.svc.cluster.local:8000"

# Secret containing CONTROL_PLANE_API_KEY, JWT_SECRET, KEYCLOAK_CLIENT_SECRET, ADMIN_API_TOKEN
# CONTROL_PLANE_API_KEY is REQUIRED for auto-registration.
# Without it, the gateway skips registration and runs in standalone mode.
secretName: stoa-gateway-secrets

# ExternalSecret (Vault-backed) β€” syncs secrets from Vault into K8s Secret
externalSecret:
enabled: true
refreshInterval: 1h
secretStoreRef: vault-backend
vaultPath: stoa/data/gateway # Must contain control_plane_api_key

The deployment template injects the secret as an environment variable:

- name: STOA_CONTROL_PLANE_API_KEY
valueFrom:
secretKeyRef:
name: stoa-gateway-secrets
key: control-plane-api-key
optional: true # Gateway runs standalone if missing
Required Vault Key

The Vault path (stoa/data/gateway) must contain a control_plane_api_key property. Without it, the ExternalSecret will create an empty key, and the gateway will skip auto-registration.

STOA Sidecar (Tier 2)​

Full configuration in charts/stoa-platform/values.yaml:

stoaSidecar:
enabled: true
targetGateway: webmethods # or kong, envoy, apigee, generic

image:
repository: ghcr.io/stoa/stoa-gateway
tag: latest

replicas: 2
environment: prod

# Control Plane connection
controlPlaneUrl: "http://control-plane-api.stoa-system.svc.cluster.local:8000"
secretName: stoa-sidecar-secrets # Must contain control-plane-api-key

# Keycloak OIDC (for token validation)
keycloakUrl: "https://auth.<YOUR_DOMAIN>"
keycloakRealm: stoa
keycloakClientId: stoa-sidecar

# Policy enforcement
policyEnabled: true

# Main gateway container (runs alongside)
mainGateway:
enabled: true
image:
repository: softwareag/webmethods-api-gateway
tag: "10.15"
port: 9072
env:
- name: EXT_AUTHZ_ENABLED
value: "true"

Console UI​

After registration, gateways appear at Console > Gateways with automatic 30-second polling (via TanStack React Query). No manual refresh needed.

ColumnDescription
NameDerived instance name
Typestoa, stoa_sidecar, webmethods, etc.
StatusONLINE, OFFLINE, DEGRADED
Environmentdev, staging, prod
Live IndicatorPulsing green dot if heartbeat received within 90s
CapabilitiesFeature badges

Status Indicators​

StatusMeaningVisual
ONLINEHeartbeat received within 90sPulsing green dot
OFFLINENo heartbeat for > 90sGray dot
DEGRADEDOnline but error rate > 5%Orange badge in detail panel

Gateway Detail Panel​

Click a gateway card to open the detail panel showing heartbeat metrics:

MetricSourceExample
Uptimehealth_details.uptime_seconds1h 30m
Routeshealth_details.routes_count15
Policieshealth_details.policies_count5
Requestshealth_details.requests_total10,000
Error Ratehealth_details.error_rate2.0%
Registered Athealth_details.registered_at2026-02-06

When the error rate exceeds 5%, the panel displays a degraded warning badge.

Deep Readiness Probe​

The gateway's /ready endpoint performs real dependency checks before reporting readiness:

  1. Control Plane connectivity β€” HTTP GET to {STOA_CONTROL_PLANE_URL}/health with 3-second timeout
  2. OIDC provider reachability β€” Fetches OIDC configuration from Keycloak (if auth is enabled)

If either check fails, the endpoint returns 503 SERVICE UNAVAILABLE with a descriptive message:

  • NOT READY: Control Plane unreachable
  • NOT READY: OIDC provider unreachable

This prevents Kubernetes from routing traffic to gateways that cannot enforce policies or validate tokens.

Config Fetch​

After registration, gateways periodically fetch their configuration from the Control Plane:

GET /v1/internal/gateways/{id}/config
Header: X-Gateway-Key: gw_xxx

The response includes:

  • pending_deployments β€” API deployments targeted at this gateway
  • pending_policies β€” Rate limiting, access control, and governance policies

This enables the Control Plane to push configuration changes to gateways without requiring a restart.

Troubleshooting​

Gateway Not Appearing in Console​

  1. Check gateway logs for registration errors:

    kubectl logs -n stoa-system deployment/stoa-gateway | grep -i register
  2. Verify Control Plane has API keys configured:

    kubectl get secret stoa-gateway-api-keys -n stoa-system -o jsonpath='{.data.GATEWAY_API_KEYS}' | base64 -d
  3. Check Control Plane logs:

    kubectl logs -n stoa-system deployment/control-plane-api | grep -i gateway
  4. Test registration endpoint manually:

    curl -X POST ${STOA_API_URL}/v1/internal/gateways/register \
    -H "X-Gateway-Key: gw_your_key" \
    -H "Content-Type: application/json" \
    -d '{
    "hostname": "test-gateway",
    "mode": "edge-mcp",
    "version": "0.1.0",
    "environment": "dev",
    "capabilities": ["rest"],
    "admin_url": "http://localhost:8080"
    }'

Gateway Shows OFFLINE​

  1. Check heartbeat is being sent:

    kubectl logs -n stoa-system deployment/stoa-gateway | grep heartbeat
  2. Verify network connectivity to Control Plane:

    kubectl exec -n stoa-system deployment/stoa-gateway -- \
    curl -s http://control-plane-api.stoa-system.svc.cluster.local:8000/health

Registration Returns 503​

Cause: GATEWAY_API_KEYS not configured in Control Plane.

Fix:

kubectl create secret generic stoa-gateway-api-keys \
--namespace stoa-system \
--from-literal=GATEWAY_API_KEYS="gw_your_key_here"

kubectl patch deployment control-plane-api -n stoa-system \
--type='json' \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/env/-", "value": {"name": "GATEWAY_API_KEYS", "valueFrom": {"secretKeyRef": {"name": "stoa-gateway-api-keys", "key": "GATEWAY_API_KEYS"}}}}]'

kubectl rollout status deployment/control-plane-api -n stoa-system

Registration Returns 401​

Cause: Gateway API key doesn't match any key in GATEWAY_API_KEYS.

Fix: Verify the key matches:

kubectl get secret stoa-gateway-api-keys -n stoa-system \
-o jsonpath='{.data.GATEWAY_API_KEYS}' | base64 -d

Security Considerations​

API Key Management​

  • Never commit keys to Git: Use Kubernetes Secrets or external secrets manager
  • Use environment-specific keys: Different keys for dev, staging, prod
  • Rotate keys periodically: Add new key β†’ update gateways β†’ remove old key
  • Audit registrations: Check Control Plane logs for unexpected registrations

Network Security​

  • Internal endpoints (/v1/internal/*) should NOT be exposed via public ingress
  • Use Kubernetes NetworkPolicies to restrict which pods can call the internal API
  • Consider mTLS for high-security deployments (future enhancement)

Key Rotation Procedure​

  1. Add new key to Control Plane (comma-separated)
  2. Restart Control Plane to pick up new key
  3. Update gateways to use new key
  4. Remove old key after all gateways updated