Skip to content

Architecture

SeyalRun is a microservices platform. Each service owns its own tables and exposes GET /health and GET /metrics; nothing but edge-proxy is published to the host.

Services

ServiceRole
edge-proxyTLS termination, HTTP → HTTPS redirect. The only service published to the host, on EDGE_HTTP_PORT / EDGE_HTTPS_PORT.
api-gatewayPublic API surface. Session handling, CORS (FRONTEND_ORIGIN), per-IP/user rate limiting via Redis.
identity-serviceUsers, auth, sessions, RBAC, Zabbix SSO exchange. Internal-only.
inventory-serviceHosts, host groups, and the AES-256-GCM credential vault. Internal-only.
terminal-serviceBrowser-based SSH terminal sessions.
recording-serviceSession recording storage and replay.
automation-serviceScripted job execution across managed hosts, Zabbix-trigger bindings.
metrics-serviceAggregated platform metrics.
zabbix-integration-serviceServes the agentless self-monitoring webhook (/webhook/zabbix/monitor) and Zabbix event integration.
frontendThe Vue 3 single-page app served to the browser.

Trust model

In plain terms: your browser only ever talks to one address. Everything behind it stays private, and nothing runs without proving who it is first.

SeyalRun request flow: Browser to edge-proxy over HTTPS, edge-proxy to api-gateway, api-gateway to identity-service, inventory-service, terminal-service, and automation-service, each requiring a security token
  • Only edge-proxy is public. It's the one address your browser ever connects to.
  • api-gateway is the front door. Every request from the browser passes through it — this is also where rate limiting and CORS are enforced.
  • Everything past that is locked. identity-service, inventory-service, and the rest can't be reached directly, even from inside the network — each one only accepts a request that carries a valid, short-lived security token (X-Service-Token, signed with SERVICE_JWT_SECRET).

The result: even if api-gateway were compromised or misconfigured, an attacker still can't walk straight into the credential vault or the identity service — the token check happens again at each one.

zabbix-integration-service is the one exception — it serves /webhook/zabbix/* directly (Zabbix calls it, bypassing api-gateway), so it checks its own secret instead: it refuses to start unless ZABBIX_WEBHOOK_HMAC_SECRET is set.

Data layer

Four databases, one engine (Postgres or MySQL, chosen via DB_ENGINE): seyalrun_identity, seyalrun_inventory, seyalrun_terminal, seyalrun_automation. ops/init-db.sh creates all four and imports the static schema (schema/<engine>/schema.sql) into identity/inventory only — terminal and automation have no static schema; their tables come entirely from each service's own Alembic migrations.

Rate limiting

api-gateway enforces per-IP/user rate limiting backed by Redis (REDIS_URL), configurable via RATE_LIMIT_REQUESTS and RATE_LIMIT_WINDOW_SECONDS.

Why this shape

Splitting identity/inventory/terminal/automation/recording/metrics into separate services means each can be scaled, migrated, and rotated independently, and a vulnerability in one (say, terminal-service, which handles live SSH sessions) doesn't automatically expose the credential vault in inventory-service — the service-token boundary is the actual security control, not just an organizational convenience.

Secure. Controlled. Automated. — Released under the Apache License 2.0.