Gateway Auto-Registration Guide
This guide explains how to configure and deploy STOA gateways with automatic registration to the Control Plane.
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:
- Derive identity from hostname + mode + environment
- Call
POST /v1/internal/gateways/register - Start heartbeat loop (every 30 seconds)
- 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β
| Variable | Required | Default | Description |
|---|---|---|---|
STOA_CONTROL_PLANE_URL | Yes | - | Control Plane API URL |
STOA_CONTROL_PLANE_API_KEY | Yes | - | Shared secret for authentication |
STOA_GATEWAY_MODE | No | edge-mcp | Gateway mode: edge-mcp, sidecar, proxy, shadow |
STOA_ENVIRONMENT | No | dev | Environment identifier for grouping |
STOA_TENANT_ID | No | - | 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}
| Hostname | Mode | Environment | Derived Name |
|---|---|---|---|
stoa-gw-abc123 | edge-mcp | prod | stoa-gw-abc123-edgemcp-prod |
kong-sidecar-xyz | sidecar | staging | kong-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
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.
| Column | Description |
|---|---|
| Name | Derived instance name |
| Type | stoa, stoa_sidecar, webmethods, etc. |
| Status | ONLINE, OFFLINE, DEGRADED |
| Environment | dev, staging, prod |
| Live Indicator | Pulsing green dot if heartbeat received within 90s |
| Capabilities | Feature badges |
Status Indicatorsβ
| Status | Meaning | Visual |
|---|---|---|
| ONLINE | Heartbeat received within 90s | Pulsing green dot |
| OFFLINE | No heartbeat for > 90s | Gray dot |
| DEGRADED | Online but error rate > 5% | Orange badge in detail panel |
Gateway Detail Panelβ
Click a gateway card to open the detail panel showing heartbeat metrics:
| Metric | Source | Example |
|---|---|---|
| Uptime | health_details.uptime_seconds | 1h 30m |
| Routes | health_details.routes_count | 15 |
| Policies | health_details.policies_count | 5 |
| Requests | health_details.requests_total | 10,000 |
| Error Rate | health_details.error_rate | 2.0% |
| Registered At | health_details.registered_at | 2026-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:
- Control Plane connectivity β HTTP GET to
{STOA_CONTROL_PLANE_URL}/healthwith 3-second timeout - 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 unreachableNOT 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β
-
Check gateway logs for registration errors:
kubectl logs -n stoa-system deployment/stoa-gateway | grep -i register -
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 -
Check Control Plane logs:
kubectl logs -n stoa-system deployment/control-plane-api | grep -i gateway -
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β
-
Check heartbeat is being sent:
kubectl logs -n stoa-system deployment/stoa-gateway | grep heartbeat -
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β
- Add new key to Control Plane (comma-separated)
- Restart Control Plane to pick up new key
- Update gateways to use new key
- Remove old key after all gateways updated
Related Documentationβ
- ADR-036: Gateway Auto-Registration β Architecture decision record
- ADR-024: Unified Gateway Architecture β Gateway modes
- ADR-035: Gateway Adapter Pattern β How CP orchestrates gateways
- WebMethods Sidecar Integration β Specific guide for WebMethods