Repository navigation
feat: node role — on-node Go buildinfo scanner with zero RBAC (ADR 0009) - #19
Merged
Merged
Conversation
Second role of the one agent binary. `agent node` runs a DaemonSet that enumerates /proc, reads debug/buildinfo from /proc/<pid>/exe (Go version, main module, dependencies, build settings incl. -pgo), and ties each process to its pod/container by parsing /proc/<pid>/cgroup. The controller role is the default, so existing invocations are unchanged. Filter early on the node: infrastructure module paths (k8s.io/, containerd, coredns, etcd, prometheus, grafana, …) and this agent's own module are dropped before any record is formed. Only four aggregate counters describe what is not kept (scanned / go found / filtered-infra / unreadable); identities of filtered or unreadable processes never leave (invariant 6). The node role holds NO Kubernetes client and NO RBAC: its ServiceAccount is bound to nothing and its token is not mounted. Privileges are hostPID plus CAP_SYS_PTRACE only — the ptrace capability is required to read other containers' /proc/<pid>/exe (non-dumpable processes), and is NOT an eBPF capability. Read-only root fs, seccomp RuntimeDefault, all other caps dropped. This resolves the CAP_SYS_PTRACE "TBD" in security.md §7. In this slice the result is written to the node role's structured log; delivery to the controller is a later slice. Infra: agent Dockerfile, image/kind-load/node-e2e make targets, raw DaemonSet manifest (deploy/node-daemonset.yaml), and a sample Go workload with a non-infra module path. e2e deploys the DaemonSet in kind and asserts the known Go process is detected with the right version and module path while infrastructure is filtered. Docs: ADR 0009; security.md §3/§4/§7/§8/§9 updated for the node role. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the agent's second role:
agent node, a DaemonSet that scans on-nodeGo binaries via
debug/buildinfo. One binary, two roles — the controllerremains the default, so existing invocations are unchanged (ADR 0009).
The scanner
/proc, readsdebug/buildinfofrom/proc/<pid>/exe: Goversion, main module, dependencies, build settings (incl.
-pgo)./proc/<pid>/cgroup(pod UID + container ID; cgroupfs and systemd driver shapes).
k8s.io/, containerd,coredns, etcd, prometheus, grafana, …) and our own
github.com/RebuildStackCo/are dropped before any record is formed. Only four aggregate counters leave
for the not-kept classes — scanned / go-found / filtered-infra / unreadable.
Identities of filtered/unreadable processes never leave (invariant 6).
Security posture (the point of the node role)
exists for it and
automountServiceAccountToken: false. It holds noKubernetes client and never calls the API.
CAP_SYS_PTRACEonly — noCAP_BPF/CAP_PERFMON. The ptracecapability is required to read other containers' non-dumpable
/proc/<pid>/exe(verified in kind); this resolves theCAP_SYS_PTRACE"TBD" in
security.md§7.RuntimeDefault, all other caps dropped,privileged: false,allowPrivilegeEscalation: false.Infra & e2e
Dockerfile;image/kind-load/node-e2emake targets.deploy/node-daemonset.yaml(no Helm chart yet, by design).test/e2e/sample/, its own module path).known Go process is detected with the right version + module path, and infra
is filtered. Passing locally:
go_found:4, filtered_infra:20withexample.com/rebuildstack-e2e/goworkloaddetected at
go1.26.1.Docs
/proc,filter policy).
security.md§3/§4/§7/§8/§9 updated.Scope
This slice writes findings to the node role's structured log; delivery to the
controller is a later slice. The one-way boundary is unchanged.
Testing
go build ./...,go test -race ./...,golangci-lint run(default +e2etag): green.make node-e2e): green.🤖 Generated with Claude Code