kubescape / kubescape/node-agent

gVisor Sentry-level event export (seccheck) is production-ready and dynamically attachable — a stronger Part B signal source than static config assumes

Open
#894 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
37
Forks
28
Avg merge
23h 31m
Merged PRs (30d)
29

Description

## Context

This is a writeup from research toward the Agent Sandbox / gVisor Runtime Visibility LFX project
(2026 Term 3), specifically Part B: node-agent's eBPF hooks attach at the kernel level, so they see
nothing happening inside a gVisor-sandboxed actor — the Sentry intercepts syscalls entirely in
userspace. The project description names three candidate signal sources to investigate, including
"Sentry-level seccomp/audit event forwarding." I read gVisor's actual source (`pkg/sentry/seccheck`)
rather than assume, and it's considerably more mature than "candidate to investigate" implies.

## What `seccheck` actually is

It's a first-class, documented, already-shipped observability API in gVisor:

- **998 documented trace points** with structured protobuf schemas — syscall enter/exit (schematized
per-syscall, e.g. `Open` has `pathname`/`flags`/`fd_path`, not just raw args), sentry-internal events,
container lifecycle (`container/start`, etc.)
- A **remote sink**: the Sentry connects *out* to a Unix domain socket and streams trace points to
whatever process is listening. No in-Sentry code changes required — this satisfies the term's own
constraint directly.
- A **reference Go server implementation already in the gVisor tree**
(`pkg/sentry/seccheck/sinks/remote/server/server.go`) to build a consumer from, so a node-agent-side
listener isn't starting from zero.

## The deployment question that actually matters

GKE Agent Sandbox controls how sandboxes get created; node-agent doesn't. So the real feasibility
question isn't "does seccheck exist," it's "can something running on the node attach to a sandbox
gVisor didn't ask it to instrument."

It can:

```
runsc --root trace create --config session.json
```

`runsc trace create` attaches a trace session to an **already-running** container by ID, dynamically,
at runtime — not only via static `--pod-init-config` at launch. Session config also supports
`ignore_setup_error` on the sink, so a session doesn't fail sandbox startup if the listening process
isn't reachable yet, which matters for a node-agent that discovers sandboxes after the fact rather than
launching them.

Concretely, this means: node-agent detects a new gVisor-sandboxed actor via whatever container-watching
it already does, shells out (or calls the equivalent client) to `runsc trace create` against that
container's ID from the host, points the resulting session's remote sink at a socket node-agent itself
listens on (reusing the reference server as a starting point), and feeds the structured protobuf events
into the existing pipeline — `processtree`'s `feeder` interface looks like the natural attachment point
for lifecycle-shaped points (`container/start`, `sentry/clone`, `sentry/task_exit`), `networkstream` for
the socket/network-shaped syscall points.

## One real limitation, stated honestly

Per the seccheck docs: *"there is a current limitation that only a single session can exist in the
system and it must be called `Default`."* For our use case (one node-agent-managed session per
sandboxed actor) that's not a blocker, but it does mean seccheck can't be layered with some other,
independent trace consumer on the same sandbox without conflict. Worth knowing before this gets
designed further, not something I'd want to gloss over.

## Additional Context

I don't have this fully prototyped yet — filing this as a design note, not a finished proof of concept,
because the actual attach/consume/feed-into-pipeline path is real engineering work I'd rather scope
properly than rush. Wanted the finding itself on record: `seccheck` + dynamic `trace create` is a
stronger, more concrete answer to "what's a feasible signal source" than the "candidate to investigate"
framing suggests, and it's worth the term prioritizing this over the file-tail (`--strace` export) or
purely-inferential (host-visible boundary signals alone) options if the single-session limitation and
the per-node `runsc trace create` privilege requirements check out under real load.

Contributor guide

Open the contributing guide

Research direction

Start with gVisor's pkg/sentry/seccheck/sinks/remote/server/server.go and the runsc trace create entry point, then inspect the existing processtree feeder and networkstream integration points. Done means validating dynamic attachment to a running sandbox, consuming remote protobuf events, routing them into the appropriate pipeline, and documenting the single-session and privilege constraints.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.