The API is designed assuming every call has direct financial impact and may access sensitive server credentials. Security requirements are therefore well above REST defaults.
Controls in place
- HMAC-SHA256: Every request is signed with HMAC-SHA256 over method, path, timestamp, nonce and body hash. Constant-time verification (hash_equals).
- AES-256-GCM: Secrets are persisted as AES-256-GCM ciphertexts only (libsodium). Master key lives outside the DB at /etc/kh-reseller-api/master.key.v{N}.
- Replay protection: Timestamp window +-300s, nonce cache 600s. A successfully signed request cannot be replayed.
- Scope-based authorization: Per-key explicit scope list. Writing and sensitive scopes must be explicitly enabled.
- IP whitelist (optional): Optional IP whitelist per key (CIDR notation, IPv4 and IPv6).
- Rate limit: Multi-layer: per key (minute + day) and per IP (minute). Token bucket with burst tolerance.
- Idempotency: Orders and destructive service actions require an Idempotency-Key. 24h replay protection against network retries.
- Tenant isolation: Every DB query hard-filters on your account id. Cross-tenant access is impossible by construction.
- Tamper-evident audit log: Every request lands in the audit log with chain hash (chain_hash[n] = sha256(chain_hash[n-1] || row_n)). Retroactive tampering is detected by hash break.
- Credentials.read alerting: Every credentials.read call produces a dedicated audit entry plus optional confirmation email to the account owner.
- SSRF-guarded webhooks: Webhook URLs are vetted before storage: HTTPS only, DNS resolution must return public IPs only (no RFC1918, no link-local).
Best practices on your side
- Store secret in a secret manager (HashiCorp Vault, AWS Secrets Manager, Doppler, 1Password), never in code, never in a git repo.
- Rotate the secret regularly (at least yearly or after personnel changes). One-click rotation in the portal, the old secret is invalidated immediately.
- One dedicated key per use case with the minimum scope (read-only if possible). No "god-mode" keys.
- If your integration runs from fixed IPs (cloud, bastion): set an IP whitelist.
- Generate the Idempotency-Key server-side and persist it; do not generate fresh on every retry. Recommendation: UUIDv4 per logical order.
- Set a webhook to your own URL; watch at least order.created and credentials.read as an event stream.
Security disclosure
Please report security issues confidentially to security@kernelhost.com. PGP key on request. Response within 24h guaranteed. Bug-bounty program in preparation.

