Each environment
- gVisor. Every environment runs under gVisor, a user-space kernel, so the code inside never talks to the host’s kernel directly.
- Its own network. Each environment has a network nothing else shares, with container-to-container traffic off. It can’t reach another environment’s address on the node.
- Its own volumes. Writable paths are volumes created for that environment and removed with it. The rest of the filesystem is read-only.
- Limits. CPU, memory and process counts come from the template. Capabilities like raw sockets are dropped, and privilege escalation is off.
Each organization
- Its own tailnet user. Every organization’s environments and sandboxes join the tailnet as that organization. A one-rule policy lets members of an organization reach only each other.
- Only what’s declared. On top of the network rules, envd in each environment accepts a connection only on a port it exports, and only from a machine of its own organization. A file share accepts generations only from the one sandbox it was wired to. Every connection, allowed or refused, is logged with its reason.
- The API. Every call is scoped to your organization: another organization’s environments, snapshots and artifacts don’t exist as far as you can tell.
Keys and tokens
- CLI tokens are per machine, shown once, stored only as a hash, and revocable from the console.
- Nodes hold no credentials. A node proves which instance it is with a signed AWS request, and the API answers with one lease’s configuration at a time. Each environment gets a single-use key to join the tailnet.
- Storage credentials are per project. A node gets credentials for a project’s snapshots only while it saves or restores one, limited to that project’s prefix, for 15 minutes.
What stays on your machine
Secret files (.env*, private keys, .netrc, secrets/, …) never leave your machine unless you name them one at a time with --file. See File sync.