Skip to content

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

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

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 (namespaces field 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_SECRET must 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=true on 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 (not debug) 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