From state.apply to revoked in under 60 seconds
Salt for declarative configuration, Vault for delivering secrets, HAProxy for TLS termination, mTLS for service-to-service authentication, and Woodpecker CI to tie it together. The result is a zero-trust runtime where access is granted by certificate, can be watched in real time, and can be revoked in seconds.
Identity is the only perimeter
Network boundaries are leaky. VPNs add latency without adding meaningful trust. The only durable answer is mTLS: every service holds a certificate, every connection is mutually authenticated, and revocation propagates in seconds — not after a quarterly review.
What we replace
- Username + password to internal servicesEasy to phish, easy to leak into logs, and often still valid long after the person who knew them has left.
- Static API keys in env varsLive forever in Git history, container images and Slack DMs.
- "Trusted" IP rangesVPN gateways and NAT traversal assume the network is the trust boundary. It isn't.
- Manual cert renewalsCalendar reminders that get missed at 02:00 on a bank holiday.
What we deliver
- mTLS everywhereEvery internal service authenticates clients by certificate. EJBCA-issued, short-lived, revocable.
- Vault as the credential brokerAppRole plus dynamic secrets. Apps fetch credentials at boot and never store them.
- Salt as the configuration substrateDeclarative state with grain-based opt-in. CI dispatches; it never bypasses.
- Live revocationRevoke a cert in EJBCA — OCSP propagates in seconds — and clients lose access. Demonstrable on every prospect call.
The components, wired together
A simplified view of the SkyQon zero-trust reference stack. Each box is something we deploy, configure and operate against your real workloads.
Salt master + minions
Salt for configuration management. Hosts opt into automated state apply via a pipeline_env grain — Root CA and HSM hosts are excluded by design. salt-api is fronted by nginx for TLS termination (a Salt 3006 cherrypy chain-bug workaround).
Vault + AppRole
KV-v2 for application secrets, AppRole for non-human authentication, CIDR-bound tokens, file audit log. Pipelines fetch secrets at runtime — no long-lived credentials in CI configs.
HAProxy + PROXY-v2
TLS termination, SNI-based routing, mTLS verification at the edge. PROXY protocol v2 to backends so client IP survives — critical for Galera authentication and audit trails.
EJBCA + ACME + REST
The CA backend issues server certs via ACME and service-account mTLS via REST. Two trust roots (Issuing G2 + Management) — explicitly separated, never conflated.
Woodpecker CI
Pipeline runners that lint, test-render, then dispatch state.apply through salt-api. Vault credentials fetched per run via AppRole — the token is revoked at step end.
Battle-tested, not bleeding edge
Every component runs in production at SkyQon and has been hardened against the gotchas you'd otherwise discover at 03:00.
Configuration
Declarative state, idempotent application, gated by host grain so safety boundaries can't be bypassed by accident.
Secrets
Short-lived tokens, CIDR-bound roles, file audit log, and dynamic secrets when the backend supports it.
Edge / proxy
TLS termination with SNI routing, mTLS verification at the edge, PROXY v2 to preserve client IPs through TCP-mode listeners.
CI / CD
Self-hosted Gitea + Woodpecker. Pipelines lint, render and dispatch through salt-api. No production access without a passing PR.
Containers / VM
Proxmox-hosted LXC for stateful services, RKE2 for stateless workloads. mTLS-protected ingress and inter-pod traffic.
Observability
One place for every pipeline event, CA audit event and mTLS handshake failure, so a single query shows the whole timeline.
Want to see the live revocation demo?
It's the headline of every prospect call. Issue a certificate from a real CA, revoke it, and watch the OCSP responder answer revoked in the same second — all in under a minute, live.