Load balancer
For production use, we recommend placing the SAS Management API behind a load balancer or an API gateway. A load balancer distributes incoming requests across appliance nodes in an HA cluster.
Reference setup — KrakenD API gateway
The following reference configuration places a KrakenD API gateway in front of two appliance nodes running the SAS Management API, with round-robin load balancing between them, TLS termination at the gateway, and pass-through of the OAuth2 bearer token to the backends.
Architecture
Client (browser, integration script, partner system)
│
│ HTTPS :5003 to <GATEWAY_FQDN>
▼
┌───────────────────────────────────────────────────┐
│ KrakenD 2.7 │
│ TLS termination + round-robin + header forward │
└──────────────────────┬────────────────────────────┘
│ HTTP :5003 (round-robin)
┌──────────────┴──────────────┐
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Appliance node 1 │ │ Appliance node 2 │
│ SAS Mgmt API │ │ SAS Mgmt API │
│ container :5003 │ │ container :5003 │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
└──────────────┬──────────────┘
▼
┌───────────────────────┐
│ SAS BlackShield DB │
│ (customer-owned) │
└───────────────────────┘
Endpoints proxied
The gateway proxies the seven SAS Management API endpoints:
| Method | Path | Auth |
|---|---|---|
| GET | /api/v1/health/live |
No |
| GET | /api/v1/tenants/{tenantCode}/users |
Yes |
| GET | /api/v1/tenants/{tenantCode}/users/{userId}/authenticators |
Yes |
| POST | /api/v1/tenants/{tenantCode}/users/{userId}/authenticators |
Yes |
| GET | /api/v1/tenants/{tenantCode}/users/{userId}/authenticators/{authId} |
Yes |
| PATCH | /api/v1/tenants/{tenantCode}/users/{userId}/authenticators/{authId} |
Yes |
| DELETE | /api/v1/tenants/{tenantCode}/users/{userId}/authenticators/{authId} |
Yes |
Prerequisites on the gateway host
-
Docker installed on the gateway host.
-
TLS certificate and private key for
<GATEWAY_FQDN>(self-signed or CA-signed). -
Port 5003/tcp open inbound from the client CIDR, and reachable to each appliance node on 5003/tcp.
-
The IP addresses or DNS names of each appliance node that hosts the SAS Management API.
docker-compose.yml
Create a docker-compose.yml in /opt/krakend/ on the gateway host:
services:
krakend:
image: devopsfaith/krakend:2.7
container_name: krakend-sas-mgmt
ports:
- "5003:8080"
volumes:
- ./krakend.json:/etc/krakend/krakend.json:ro
- ./certs:/etc/krakend/certs:ro
command: ["run", "-c", "/etc/krakend/krakend.json"]
networks:
- krakend-network
restart: unless-stopped
networks:
krakend-network:
driver: bridge
name: krakend-sas-mgmt-network
krakend.json
Create /opt/krakend/krakend.json with one entry per endpoint. The example below shows two endpoints; add the remaining six using the same pattern. Replace NODE_1_IP and NODE_2_IP with the IP addresses of your appliance nodes:
{
"$schema": "https://www.krakend.io/schema/v2.7/krakend.json",
"version": 3,
"name": "SAS PCE Enterprise Virtual Appliance — SAS Management API gateway",
"port": 8080,
"timeout": "30000ms",
"tls": {
"public_key": "/etc/krakend/certs/cert.pem",
"private_key": "/etc/krakend/certs/key.pem"
},
"extra_config": {
"telemetry/logging": {
"level": "INFO",
"prefix": "[KRAKEND]",
"stdout": true,
"format": "default"
},
"router": {
"return_error_msg": true
}
},
"endpoints": [
{
"endpoint": "/api/v1/health/live",
"method": "GET",
"output_encoding": "no-op",
"input_headers": ["Content-Type", "Accept"],
"backend": [
{
"url_pattern": "/api/v1/health/live",
"encoding": "no-op",
"method": "GET",
"sd": "static",
"host": [
"http://NODE_1_IP:5003",
"http://NODE_2_IP:5003"
]
}
]
},
{
"endpoint": "/api/v1/tenants/{tenantCode}/users",
"method": "GET",
"output_encoding": "no-op",
"input_headers": ["Authorization", "Content-Type", "Accept"],
"backend": [
{
"url_pattern": "/api/v1/tenants/{tenantCode}/users",
"encoding": "no-op",
"method": "GET",
"sd": "static",
"host": [
"http://NODE_1_IP:5003",
"http://NODE_2_IP:5003"
]
}
]
}
]
}
Deploy
-
Stage the configuration on the gateway host:
sudo mkdir -p /opt/krakend/certssudo cp krakend.json /opt/krakend/sudo cp docker-compose.yml /opt/krakend/ -
Replace the backend placeholders with your appliance node IP addresses:
sudo sed -i "s/NODE_1_IP/<node1-ip>/g" /opt/krakend/krakend.jsonsudo sed -i "s/NODE_2_IP/<node2-ip>/g" /opt/krakend/krakend.json -
Copy the gateway TLS certificate and private key:
sudo cp /path/to/cert.pem /opt/krakend/certs/cert.pemsudo cp /path/to/privkey.pem /opt/krakend/certs/key.pemsudo chmod 644 /opt/krakend/certs/cert.pem /opt/krakend/certs/key.pemKrakenD 2.7 runs as UID 1000 inside the container; bind-mounted key files with mode
640androot:rootownership are unreadable. Use mode644or change ownership to1000:1000before launching. -
Start the gateway:
cd /opt/krakend && sudo docker compose up -d -
Verify the gateway is listening and that both backends are reachable:
sudo docker logs krakend-sas-mgmt --tail 20curl -ks https://<GATEWAY_FQDN>:5003/api/v1/health/livesudo docker logs --tail 20 krakend-sas-mgmt | grep health/liveRepeated calls should alternate between the two appliance-node IPs in the gateway log, confirming that round-robin load balancing is working.
Failover tuning
The sample configuration uses the default KrakenD request timeout of 30 seconds and does not enable a circuit breaker. During a backend outage, requests routed to the failed appliance node wait for the timeout to expire before returning an error. To reduce failover latency, configure per-backend request timeouts, retries, and a circuit breaker — refer to the KrakenD documentation for the exact syntax at https://www.krakend.io/docs/backends/circuit-breaker/ and https://www.krakend.io/docs/backends/timeouts/.