mirror of
https://github.com/zap-proto/zip.git
synced 2026-10-19 15:38:57 +00:00
Attest the pod a unix peer runs in
SO_PEERCRED names the process; the kubelet's cgroup names the pod it was placed in. A server on a socket shared across pods needs the second to scope what the first may read, and neither is a value the caller states.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
//go:build linux
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// podRE matches the pod segment the kubelet writes into a container's cgroup
|
||||
// path under either cgroup driver: `kubepods-burstable-pod<uid>.slice` for
|
||||
// systemd, where the uid's dashes become underscores, and
|
||||
// `/kubepods/burstable/pod<uid>` for cgroupfs.
|
||||
var podRE = regexp.MustCompile(`pod([0-9a-f]{8})[-_]([0-9a-f]{4})[-_]([0-9a-f]{4})[-_]([0-9a-f]{4})[-_]([0-9a-f]{12})`)
|
||||
|
||||
// PodUID returns the UID of the Kubernetes pod the peer process runs in, read
|
||||
// from the cgroup the kubelet placed it in, or "" for a process outside any
|
||||
// pod. The kernel wrote the cgroup and the kubelet named it, so like the peer
|
||||
// itself it is a fact about the caller and not a value the caller states.
|
||||
func (p *Peer) PodUID() string {
|
||||
if p == nil || p.PID <= 0 {
|
||||
return ""
|
||||
}
|
||||
b, err := os.ReadFile("/proc/" + strconv.Itoa(p.PID) + "/cgroup")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return podUID(string(b))
|
||||
}
|
||||
|
||||
func podUID(cgroup string) string {
|
||||
m := podRE.FindStringSubmatch(cgroup)
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(m[1:], "-")
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//go:build linux
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPodUIDReadsTheKubeletsCgroupUnderEitherDriver(t *testing.T) {
|
||||
const uid = "e03401ab-1ff2-44e3-8260-3d175888e4a7"
|
||||
cases := map[string]string{
|
||||
"systemd besteffort": "0::/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pode03401ab_1ff2_44e3_8260_3d175888e4a7.slice/cri-containerd-2acff90d.scope\n",
|
||||
"systemd burstable": "0::/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pode03401ab_1ff2_44e3_8260_3d175888e4a7.slice/cri-containerd-2acff90d.scope\n",
|
||||
"systemd guaranteed": "0::/kubepods.slice/kubepods-pode03401ab_1ff2_44e3_8260_3d175888e4a7.slice/cri-containerd-2acff90d.scope\n",
|
||||
"cgroupfs": "0::/kubepods/burstable/pode03401ab-1ff2-44e3-8260-3d175888e4a7/2acff90d\n",
|
||||
"cgroup v1": "12:pids:/kubepods/besteffort/pode03401ab-1ff2-44e3-8260-3d175888e4a7/2acff90d\n11:memory:/kubepods/besteffort/pode03401ab-1ff2-44e3-8260-3d175888e4a7/2acff90d\n",
|
||||
}
|
||||
for name, cg := range cases {
|
||||
if got := podUID(cg); got != uid {
|
||||
t.Errorf("%s: got %q, want %q", name, got, uid)
|
||||
}
|
||||
}
|
||||
for name, cg := range map[string]string{
|
||||
"host process": "0::/user.slice/user-1000.slice/session-3.scope\n",
|
||||
"docker, no pod": "0::/system.slice/docker-2acff90d.scope\n",
|
||||
"uid too short": "0::/kubepods.slice/kubepods-pode03401ab_1ff2.slice\n",
|
||||
"empty": "",
|
||||
} {
|
||||
if got := podUID(cg); got != "" {
|
||||
t.Errorf("%s: got %q, want no pod", name, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A peer outside Kubernetes is not a pod, and a peer the kernel never attested
|
||||
// is not one either.
|
||||
func TestPodUIDIsEmptyOffCluster(t *testing.T) {
|
||||
if os.Getenv("KUBERNETES_SERVICE_HOST") != "" {
|
||||
t.Skip("running inside a pod")
|
||||
}
|
||||
if got := (&Peer{PID: os.Getpid()}).PodUID(); got != "" {
|
||||
t.Fatalf("this process reads as pod %q", got)
|
||||
}
|
||||
var none *Peer
|
||||
if got := none.PodUID(); got != "" {
|
||||
t.Fatalf("nil peer reads as pod %q", got)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//go:build !linux
|
||||
|
||||
package zip
|
||||
|
||||
// PodUID is "" where there is no cgroup to read.
|
||||
func (p *Peer) PodUID() string { return "" }
|
||||
Reference in New Issue
Block a user