Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/k8s/sam-box-canary-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ metadata:
namespace: sam-canary-${ENV_NAME}
data:
resolv.conf: |
nameserver 169.254.1.1
nameserver 100.127.255.253
---
apiVersion: v1
kind: ServiceAccount
Expand All @@ -43,8 +43,8 @@ metadata:
# nano-init makes its own with --create-namespaces and gives itself the only
# route out; the agent then speaks ordinary HTTP to ordinary names, and the
# fact that it reaches anything at all is the assertion. A curl pointed at
# --socks5-hostname would prove the boundary works for a client that chose to
# use it, which is the one case nobody needs proving.
# --proxy would prove the boundary works for a client that chose to use it,
# which is the one case nobody needs proving.
apiVersion: apps/v1
kind: Deployment
metadata:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ go.work.sum
# .vscode/
#
bin/
dist/
# Stray binaries from `go build ./cmd/<name>/` in the repo root
/sam-node
/sam-box
Expand Down
24 changes: 21 additions & 3 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
version: 2
project_name: sam
# Deliberately not released: sam-bench (a measurement instrument for people
# working on the mesh, built from the repo, not something operators install)
# and chaos-agent (a Python dev tool).
builds:
- id: sam-node
main: ./cmd/sam-node
Expand Down Expand Up @@ -71,6 +74,20 @@ builds:
- arm64
ldflags:
- -s -w
- id: sam-console
main: ./cmd/sam-console
binary: sam-console
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
ldflags:
- -s -w
- id: nano-init
main: .
# nano-init is its own module: it carries a userspace TCP stack, and that
Expand All @@ -79,9 +96,10 @@ builds:
binary: nano-init
env:
- CGO_ENABLED=0
# linux only: nano-init is PID 1 inside a Linux sandbox — TUN ioctls,
# netlink, namespaces and vsock have no meaning anywhere else.
goos:
- linux
- darwin
goarch:
- amd64
- arm64
Expand All @@ -101,6 +119,6 @@ archives:
- goos: windows
formats:
- zip
# nano-init has no windows build (see build id "nano-init" above), so the
# windows archive intentionally has one fewer binary than linux/darwin.
# nano-init only builds for linux (see build id "nano-init" above), so the
# windows and darwin archives intentionally have one fewer binary.
allow_different_binary_count: true
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ You are an expert software engineering assistant helping to develop, maintain, a
## 1. Architecture & Component Independence
* **Decoupled Architecture:** The `sam-control-plane`, `sam-router` and `sam-node` components are strictly independent. They must not share internal state or tightly couple their logic.
* **API Communication:** All data communication between `sam-control-plane`, `sam-router` and `sam-node` must happen exclusively via the common API defined in `api/sam.proto`.
* **Sandbox Dataplane:** `sam-box` (one per sandbox) is the single egress policy enforcement point. It holds no libp2p host, no enrollment and no mesh identity, and reaches the mesh exclusively as a client of the local `sam-node` sidecar socket. `nano-init` (PID 1 inside the guest, its own Go module) owns the guest side. The sandbox boundary is a Unix socket: SOCKS5 out, `CONNECT <port>` back in. The authoritative design is `site/content/docs/agent-architecture.md`; do not contradict it.
* **Sandbox Dataplane:** `sam-box` (one per sandbox) is the single egress policy enforcement point. It holds no libp2p host, no enrollment and no mesh identity, and reaches the mesh exclusively as a client of the local `sam-node` sidecar socket. `nano-init` (PID 1 inside the guest, its own Go module) owns the guest side; its datapath is the `tun2connect` library. The sandbox boundary is a Unix socket speaking named HTTP tunnels: CONNECT (TCP) and connect-udp (UDP) out, `CONNECT <port>` back in. The authoritative design is `site/content/docs/agent-architecture.md`; do not contradict it.
* **Enforcement over Convention:** never gate sandbox traffic on the agent's cooperation — no proxy environment variables, no `LD_PRELOAD` shims, no DNS spoofing. The agent harness stays unmodified and mesh-unaware; confinement is a route and a socket, built by the userspace launcher (`nano-init`) and judged in `sam-box`. An agent that must cooperate with its own confinement is not confined.
* **Policy on Names:** egress policy, secret injection and routing decisions are made on the destination *name*, never on an IP. Deny by default.
* **Agent Identity:** the agent is the principal; the node is only the channel. Agent identity comes from the platform's workload credential, verified at admission — never asserted in-band from inside the sandbox. Platforms integrate solely through the connector interface (`Attach`/`Detach`/`Refresh`/`Status` and the agent bundle), not by reaching into SAM internals.
Expand Down
6 changes: 3 additions & 3 deletions api/sam.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions api/sam.proto
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,9 @@ message AgentAttachRequest {
}

message AgentAttachResponse {
// Sandbox boundary endpoints to wire into the sandbox: SOCKS5 for guest to
// host, and a reverse channel for host to guest that is empty when the
// bundle declares no ingress.
// Sandbox boundary endpoints to wire into the sandbox: named HTTP tunnels
// (CONNECT, connect-udp) for guest to host, and a reverse channel for host
// to guest that is empty when the bundle declares no ingress.
string egress_socket = 1;
string ingress_socket = 2;
string error = 3;
Expand Down
32 changes: 19 additions & 13 deletions cmd/nano-init/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,28 @@ boundary, and then gets out of the agent's way.

## What it does

1. **Builds the only way out.** Creates `tun0` over netlink, gives it a
link-local address, and makes it the default route. There is no other
interface in the sandbox, so this is not the preferred path out; it is the
only one.
2. **Carries a TCP stack.** Terminates the sandbox's TCP in userspace via
gVisor (through `tun2socks`) and opens a SOCKS5 flow to the boundary for
each connection.
3. **Keeps the name.** Answers DNS with a placeholder address per name and
remembers the pairing, so what reaches the boundary is `mesh.sam.alt` rather
than an address. The boundary chooses a provider from the name, which is the
entire reason the name has to survive the trip.
1. **Builds the only way out.** Creates `tun0` over netlink and gives it the
guest ends of the synthetic address pools (`100.64.0.0/10`, `100::/64`).
There is no other interface in the sandbox, so this is not the preferred
path out; it is the only one.
2. **Carries a TCP stack.** Terminates the sandbox's TCP/IP in userspace via
the [tun2connect](https://github.com/aojea/agents.net) library (gVisor's
netstack) and opens one named HTTP tunnel to the boundary per flow:
authority-form `CONNECT` for TCP, `connect-udp` for UDP.
3. **Keeps the name.** The virtual DNS answers with a synthetic address per
name and remembers the pairing, so what reaches the boundary is
`mesh.sam.alt` rather than an address. The boundary chooses a provider from
the name, which is the entire reason the name has to survive the trip. A
flow to an address the guest never resolved has no name, and is refused.
4. **PID 1 duties.** Reaps orphans, propagates `SIGINT`/`SIGTERM`/`SIGQUIT` to
the child's process group, and exits with the agent's own status.

It is a separate Go module. A userspace TCP stack is a large dependency and has
no business in the graph every other SAM binary builds from.
no business in the graph every other SAM binary builds from. The datapath —
engine, tunnel client, virtual DNS — is the tun2connect library, consumed here
rather than forked: what this module owns is exactly the SAM- and
platform-specific part, the vsock boundary for microVMs, `--create-namespaces`
for pods, `copy` for image builds, and PID 1.

## What it deliberately does not do

Expand Down Expand Up @@ -79,4 +85,4 @@ image that has nothing else in it.
- [Running agents on SAM](https://sam-mesh.dev/docs/user/running-agents/) — the
full picture, including the microVM arrangement
- [Agent architecture](https://sam-mesh.dev/docs/agent-architecture/) — why the
boundary speaks SOCKS5
boundary speaks named HTTP tunnels
197 changes: 0 additions & 197 deletions cmd/nano-init/boundary.go

This file was deleted.

Loading
Loading