Threat model
Source:
docs/15-threat-model.mdat2081f31a099e· docs version 0.4.0
This document defines the security model for a tentaflake host running long-lived, potentially compromised AI agents. It describes the intended boundaries of the generic template. A deployment fork must add a target-host review, credential inventory, tailnet policy, provider policy, and recovery evidence.
Security objective
Section titled “Security objective”The balanced profile assumes that prompts, retrieved content, dependencies,
and the agent process can become hostile. Compromise of one controller should
not by itself grant access to host secrets, another agent, direct Internet or
LAN egress, a privileged container runtime, or an unrestricted host shell.
Required external access is mediated by narrow host services. Risky local code
execution is delegated to a disposable, offline worker.
The dev profile is a compatibility mode, not a security boundary. The
strict profile fails evaluation because a tested separate-kernel boundary is
not yet implemented. There is no silent downgrade to either profile.
Assets
Section titled “Assets”The model protects:
- the host kernel, NixOS configuration, boot state, container engine, and system services;
- operator access, tailnet identity, and recovery authority;
- provider, Git, backup, signing, and deployment credentials;
- agent workspaces, broker audit records, backups, and operational logs;
- other agents and their state, credentials, budgets, and broker endpoints;
- external provider accounts, repositories, websites, and cost budgets;
- the integrity and availability of the declarative configuration and pinned software artifacts.
Adversaries and failure modes
Section titled “Adversaries and failure modes”The design considers:
- prompt injection or malicious model output controlling an agent;
- hostile documents, websites, repositories, packages, and generated code;
- a compromised or malicious controller image or dependency;
- attempts to escape a container, abuse a Linux capability, exhaust resources, scan local networks, reach metadata services, or steal runtime credentials;
- cross-agent access, broker impersonation, SSRF, DNS rebinding, redirect abuse, request smuggling through oversized inputs, and cost exhaustion;
- unauthorized Git pushes or external side effects;
- a remote attacker reaching an accidentally published management service;
- operator error, stale backups, policy drift, storage exhaustion, service crash loops, and incomplete monitoring;
- supply-chain substitution of a mutable or unauthorized container image.
Denial of service against the whole host through a kernel, storage, container engine, or hardware failure is reduced but not eliminated.
Trust assumptions
Section titled “Trust assumptions”The following remain trusted computing base or operator assumptions:
- the physical machine, firmware, host kernel, NixOS closure, systemd, Nix evaluation, and the operator account;
- the selected Docker or Podman engine, gVisor
runsc, firewall, filesystem, and their correct activated configuration; - the deployment fork’s runtime secret provisioning and file ownership;
- reviewed image-signing identities and keys when provenance enforcement is enabled;
- correct provider, repository, backup, tailnet, DNS, and alerting policy owned outside this generic template;
- operators review the exact build and target before activation and perform real restore and incident-response drills.
An image digest gives reproducible identity, not trust. Cosign verification shows only that the configured signer authorized that exact artifact. Neither claim proves that the software is benign.
Trust boundaries and data flows
Section titled “Trust boundaries and data flows”Operator to host
Section titled “Operator to host”Management enters through the operator account and an explicitly installed tailnet grants/SSH policy. Tentaflake does not publish its CLI or observability listeners to a public interface. Tailscale transport alone is not authorization, and the template cannot verify the remote control-plane policy.
Host to controller capsule
Section titled “Host to controller capsule”The host starts a digest-pinned controller with runsc, a non-root user, no
added capabilities, a read-only root filesystem, bounded resources, selected
AppArmor/Seccomp policy, and only declared mounts. Secure profiles reject host
networking, published ports, extra devices, unconfined overrides, sensitive
mounts, mutable image tags, and direct provider credential files.
Caller-supplied host user-namespace overrides are rejected. The current
root-managed Docker/Podman paths do not prove daemon-level host UID remapping:
Docker remapping would change every persistent bind-mount owner, and Podman’s
keep-id/nomap modes are rootless-only. runsc and the non-root container
UID are enforced boundaries; separate host UID mapping remains an explicit
residual risk until an ownership migration and both runtime paths are tested.
The controller workspace is persistent and writable. An optional exact-size filesystem bounds that workspace, but the controller may still corrupt or delete its own data. State outside that mount needs separate capacity policy.
Controller to external services
Section titled “Controller to external services”A balanced controller either has network=none or joins one agent-specific
internal bridge. The bridge exposes only that agent’s host LLM and fetch
brokers. Deterministic interface and source-subnet firewall rules reject
forwarding and unrelated host services. The controller receives only a
runtime virtual key, never the upstream credential.
The LLM broker enforces exact routes and models, clamps completion size, and applies concurrency, rate, token, and cost budgets. The fetch broker permits only configured HTTPS hosts and media types, resolves public addresses, pins the connection address, revalidates redirects, ignores environment proxies, bounds responses, and labels returned content as untrusted. These controls do not make retrieved content safe to execute or trust.
Controller to disposable worker
Section titled “Controller to disposable worker”The worker receives a bounded, descriptor-safe workspace snapshot and runs a
short-lived runsc capsule with no network or secrets. It returns artifacts
through a controller-specific read-only import. Only local-reversible
actions run automatically; other permitted classes wait for a host-side
approval record, and forbidden is rejected.
This boundary cannot prove that every tool exposed by every upstream agent runtime routes shell or file work through the worker. Runtime-specific tool configuration remains a deployment review item. Approval also does not grant network access or implement a generic external-action adapter.
Host to external systems
Section titled “Host to external systems”Git auto-push, backups, provider access, signature verification, remote tailnet policy, and alert delivery execute with host-held authority. Their credentials remain runtime files or systemd credentials. Each integration must be narrowly scoped by the deployment: exact repository and branch, provider account and models, backup repository, signer identity, tailnet grants, and alert receiver.
Telemetry and detection
Section titled “Telemetry and detection”Systemd journals are the primary local audit trail; there is no custom SQLite audit database or web console. The optional Alloy/Loki/Prometheus/Grafana profile is loopback-only and supplies baseline metrics and rules. The separate Falco profile detects selected runtime behavior but does not prevent it. Retention, off-host evidence, notification delivery, and sensitive-log review remain deployment responsibilities.
Control and evidence map
Section titled “Control and evidence map”| Risk | Primary control | Required evidence |
|---|---|---|
| Host or peer access | gVisor capsule, mounts, capabilities, firewall | eval, build, live inspect, negative VM test |
| Direct egress | internal per-agent bridge and broker-only rules | activated firewall plus DNS/LAN/metadata tests |
| Credential theft | host-held credentials and virtual broker key | generated unit and live mount/environment review |
| SSRF and rebinding | fetch allowlist, public-IP checks, pinned DNS | broker tests and target-host broker health |
| Cost exhaustion | rate, concurrency, token, and cost budgets | policy review, audit output, alerts |
| Unsafe code execution | disposable offline worker and approval classes | queue, timeout, cleanup, and no-egress tests |
| Unauthorized Git write | exact remote and branch host helper | denial tests and least-privilege credential review |
| Mutable image substitution | digest pin and optional Cosign start gate | verified policy plus failed-signature start test |
| Resource exhaustion | memory, CPU, PID, tmpfs, log, and workspace limits | live limits and exhaustion tests |
| Lost state | encrypted Restic policy and success freshness | real fresh-host restore drill |
| Runtime anomaly | journald, optional observability and Falco | retention, receiver, and response drill |
| Remote management exposure | loopback listeners and tailnet policy template | live listeners and remote policy audit |
Source inspection proves intended code. Nix evaluation proves option types and assertions. A successful build proves the closure. VM tests prove only their fixture. Activation changes a particular host. Live inspection and adversarial tests are required before calling that host secure. Unavailable AF_UNIX, container-inspect, tailnet, broker, backup, or alert evidence is unknown, never green.
Explicit non-goals and residual risks
Section titled “Explicit non-goals and residual risks”Tentaflake does not:
- make Docker, Podman, gVisor, the kernel, firmware, or hardware immune to vulnerabilities;
- provide a tested MicroVM or separate-kernel
strictprofile today; - attest that a signed image, model, dependency, website, or generated artifact is safe or correct;
- prevent an agent from damaging its own writable workspace;
- transparently mediate every tool in every supported upstream agent runtime;
- provide generic adapters for arbitrary purchases, messages, deployments, or other external side effects;
- configure production tailnet grants, provider accounts, registry trust, backup storage, Grafana retention, Alertmanager delivery, or off-host logs;
- guarantee availability under host-wide storage, kernel, engine, network, power, or hardware failure;
- replace patch management, key rotation, capacity planning, incident response, or human review of requested actions.
Falco and observability improve detection. Backups improve recovery. Neither is a preventive isolation boundary. A deployment must document accepted residual risks and the owner of every external control before unattended operation.
Deployment acceptance checklist
Section titled “Deployment acceptance checklist”Before treating a host as ready for unattended agents:
- Keep every untrusted controller on
balanced; confirmstrictstill fails closed and document any deliberatedevexception. - Review generated units, exact mounts, identities, resource limits, image digests, provenance policies, and agent-specific broker policy.
- Build and run the unit, module-evaluation, and VM suites without activating the production host as a side effect.
- Review and separately approve the exact host activation.
- Run
tentaflake doctor --security, live OCI inspection, listener checks, and direct-egress, LAN, metadata, peer, and broker negative tests. - Audit the deployed tailnet grants/SSH policy and all external credentials for least privilege and rotation.
- Configure log retention, capacity alerts, notification delivery, and an operator response path; validate them end to end.
- Perform a real encrypted backup and fresh-host restore drill.
- Record remaining unknown evidence and accepted residual risks. Do not count a warning or unavailable check as a pass.