Security¶
Security architecture and hardening guide for self-hosted HX-SDP deployments.
Authentication model¶
HX-SDP uses a two-layer authentication model:
| Layer | Credential | Scope | Storage |
|---|---|---|---|
| Tenant | API key (hx_live_...) |
Data-plane operations | SHA-256 hashed in tenant registry |
| Admin | Service key (HX_GATE_ENGINE_SERVICE_KEY) |
Admin + inter-service auth | Environment variable |
- API keys are generated during tenant onboarding and shown once. They cannot be recovered — only rotated.
- The service key authenticates Gate → Engine traffic and all admin endpoints.
Key management¶
Generate a service key¶
# Cryptographically random, 64-char hex string
python3 -c "import secrets; print(secrets.token_hex(32))"
Rotate tenant keys¶
curl -X POST https://gate.holonomx.com/gate/onboard/rotate-key \
-H "Authorization: Bearer $SERVICE_KEY" \
-H "Content-Type: application/json" \
-d '{"tenant_id": "acme-corp"}'
The old key is immediately invalidated. Update all client applications before rotating.
Key storage best practices¶
- Store the service key in a secrets manager (Vault, AWS Secrets Manager, GCP Secret Manager)
- Never commit keys to version control
- Use Docker secrets or Kubernetes secrets for container deployments
- Rotate keys quarterly or immediately after any suspected compromise
TLS¶
Enable TLS on Engine¶
HOLONOMIX_TLS_CERT_PATH=/etc/ssl/certs/hx-engine.pem
HOLONOMIX_TLS_KEY_PATH=/etc/ssl/private/hx-engine-key.pem
Reverse proxy TLS (recommended)¶
For production, terminate TLS at a reverse proxy (nginx, Caddy, Traefik) in front of HX-Gate:
server {
listen 443 ssl http2;
server_name gate.holonomx.com;
ssl_certificate /etc/ssl/certs/gate.pem;
ssl_certificate_key /etc/ssl/private/gate-key.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Network isolation¶
Recommended network topology¶
Internet
│
▼
┌──────────────┐
│ TLS Proxy │ ← Only public-facing service
│ (443) │
└──────┬───────┘
│ (internal network)
┌──────▼───────┐ ┌────────────┐ ┌───────┐
│ HX-Gate │────▶│ HX-Engine │ │ Redis │
│ (8080) │ │ (8000) │ │(6379) │
└──────────────┘ └────────────┘ └───────┘
Rules:
- Only the TLS proxy is exposed to the internet
- HX-Gate, HX-Engine, and Redis communicate on an internal Docker network
- Engine port (8000) is never exposed externally
- Redis port (6379) is never exposed externally
Docker Compose enforces this by default — the engine and Redis services do not publish ports to the host.
Namespace isolation¶
Tenants are restricted to their authorized namespaces via ACL:
- Each tenant has a list of allowed namespaces (
namespacesfield in tenant registry) - Requests to unauthorized namespaces return
403 - Cross-tenant data access is not possible — even with a valid key, the namespace ACL is enforced
Audit trail¶
Every operation is logged to an append-only JSONL file:
{
"ts": "2026-01-15T10:30:42.123Z",
"tenant_id": "acme-corp",
"method": "POST",
"path": "/v1/put",
"namespace": "production",
"status": 200,
"cus": 1.0,
"latency_ms": 42.3,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
- Enabled by default (
HX_GATE_AUDIT_ENABLED=true) - Location:
HX_GATE_AUDIT_LOG_PATH(default:/var/log/hx-gate/audit.jsonl) - Ship to your SIEM (Splunk, Elastic, Datadog) for centralized analysis
Stripe webhook verification¶
All incoming Stripe webhook events are verified using HMAC signature validation:
stripe.Webhook.construct_event(
payload=body,
sig_header=request.headers["Stripe-Signature"],
secret=config.stripe_webhook_secret,
)
- Events with invalid signatures are rejected with
400 - The
HX_GATE_STRIPE_WEBHOOK_SECRETmust match the Stripe dashboard webhook configuration
CORS¶
CORS is disabled by default. Enable it only for specific origins:
# Allow specific origins (recommended)
HX_GATE_CORS_ORIGINS=https://app.example.com,https://dashboard.example.com
# Never use * in production
Input validation¶
- Max upload size: Controlled by
HOLONOMIX_MAX_UPLOAD_BYTES(default: 100 MB). Requests exceeding this are rejected before processing. - Key format: Keys are validated against length and character constraints.
- Namespace format: Max 255 characters, alphanumeric plus
-and_. - API key format: Minimum 32 characters, validated on creation.
Hardening checklist¶
- Service key is ≥32 characters and stored in a secrets manager
-
HOLONOMIX_REQUIRE_AUTH=trueon the engine - TLS enabled (proxy or native)
- Engine and Redis ports not exposed to the internet
- Audit logging enabled and shipped to SIEM
- CORS restricted to known origins
- Stripe webhook secret configured (if billing enabled)
- Log level set to
info(notdebug) in production - Rate limiting enabled per tenant
- Tenant API keys rotated on schedule
- Docker images pinned to specific tags (not
latest) - Regular security updates applied to base images