Docs / Security

Security model

The precise mechanics behind every control — exactly what each layer checks, and what it deliberately doesn't. For the pitch and the trust-boundary picture, start with the security overview; this page is the reference your security team reads next.

The short version: emisar is a curated allowlist with an audit envelope, not a sandbox. Restarting Cassandra still restarts Cassandra — the value is the narrow attack surface and the audit trail, not process isolation.

The trust boundary

  1. Pre-approved actions only. The runner loads action YAMLs at boot and refuses anything not in the catalog. A model that asks for rm -rf / can't issue it — the request never reaches a shell.
  2. Outbound-only network. Runners dial the control plane over TLS. No inbound ports, no SSH bastion to compromise.
  3. Bootstrap key + per-runner token. The enrollment key (emkey-auth-…) is a one-time secret. The runner exchanges it for a long-lived per-runner token (rnrtok-…) on first connect. Single-use keys are atomically consumed: two concurrent registrations can never both succeed.
  4. Argument validation on the runner. The runner is the authority on arguments: it validates every arg against the action's declared schema — rejecting anything undeclared, coercing types, and enforcing each arg's min/max — before it executes. The control plane gates the dispatch (policy, scope, pack trust); a misbehaving cloud cannot smuggle an undeclared argument past the runner.
  5. Policy. Two-layer per-account model: a default decision per risk tier (low / medium / high / critical), plus ordered per-action overrides that glob-match on action ID. First matching override wins; otherwise the tier default applies. Decisions: allow / require_approval / deny. Higher-risk tiers are forced to be at least as restrictive as lower-risk ones — you can't allow cassandra.nodetool_drain while requiring approval for cassandra.nodetool_status. Shipped defaults: low and medium allow, high require_approval, critical deny. The runner sees the decision only; it doesn't reason about policy.
  6. Approvals. When policy demands approval, the run is held until an authorised teammate decides. Approvers are emailed; clicking the link lands them on the request page.
  7. Output redaction. 20+ built-in patterns — bearer/basic auth, JWTs, AWS keys, Google API keys, GitHub tokens, private-key blocks, and common password= / secret= / token= assignments — are masked before the chunk leaves the runner. Per-action rules layer on top, and per-rule hit counts are recorded so you can see what was masked. The control plane never receives the raw bytes.
  8. Limits. Every action has a timeout and stdout/stderr byte ceiling. Cloud opts can lower these but not raise them above the action's declared maximum.
  9. Searchable cloud audit + hash-chained runner journal. Cloud-side, every mutation — dispatch, approval, runner state change, policy edit, sign-in — appends an account-scoped audit event. Those events ship as NDJSON over GET /api/audit — forward-only with keyset cursor pagination and RFC 5988 Link headers — gated on an audit:read-scoped API key minted from the audit page. Point any SIEM that speaks HTTP at it; that token reads events but never executes an action. Runner-side, every action attempt writes a JSONL line to /var/log/emisar/events.jsonl with a previous-line hash — that's the host-side forensics copy. emisar audit verify detects tampering in the local journal.
  10. Setuid drop on Linux. Actions with user: set drop the child process to that local user's uid and primary gid before exec. A runner shipping under a privileged service account still runs the declared action as the lower-privilege user.
  11. Local action admission (defense-in-depth). The runner config supports an admission.allow / admission.deny list of glob patterns over action ids (e.g. cassandra.*, *.repair). Blocked actions are hidden from the catalog this runner advertises to cloud AND refused at execution time, so even a compromised portal cannot push something the host operator did not sanction. Refusals land in the JSONL audit log as action_blocked_by_admission events for SIEM alerting.

What emisar is not

  • Not a VM, container, or kernel sandbox. Process isolation is the host's job (use systemd hardening, namespaces, SELinux, gVisor — we recommend all of those).
  • Not an EDR. emisar doesn't detect malicious binaries, lateral movement, or host compromise. It detects tampering in the local runner journal and rejects a pack whose on-disk contents no longer match the cloud-pinned trusted hash before execution.
  • Not a replacement for OS-level access control. The user: drop only works because the OS already permits it.