Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pod mapping via cgroup ids #2776

Merged
merged 34 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b4e0f1d
rthooks: fix comments
kkourt Aug 6, 2024
981f649
grpc: propagate errors in RuntimeHook call
kkourt Aug 6, 2024
ba3acdc
rthooks: oci-hook add comments for container name
kkourt Aug 6, 2024
c067fe5
rthooks: add containerID, pod{Name,ID,Namespace}
kkourt Aug 6, 2024
c77aa9a
autochore: make protogen && make vendor
kkourt Aug 7, 2024
38ae618
oci-hook: fill ContainerID, Pod{Name,UID,Namespace}
kkourt Aug 7, 2024
79b3bf5
minikube-install-hook.sh: use tabs
kkourt Aug 7, 2024
0421fc1
rthooks: move minikube install script
kkourt Aug 7, 2024
7257873
rthooks: move rt detection in a helpers file
kkourt Aug 7, 2024
54d1606
minikube-test-hook.sh: test hook using minikube
kkourt Aug 7, 2024
020ee62
gha: add tetragon-rthooks workflow
kkourt Aug 7, 2024
05c22a3
policyfilter: abort if we cannot get state
kkourt Aug 7, 2024
1016aa4
rthooks: introduce CgroupID()
kkourt Aug 7, 2024
f3b579d
rthooks: introduce PodID()
kkourt Aug 7, 2024
ab636e6
rthooks: use PodUID from request
kkourt Aug 7, 2024
d47d15e
rthooks: introduce ContainerID()
kkourt Aug 7, 2024
6172abe
rthooks: ContainerID() support crio paths
kkourt Aug 7, 2024
47f4ce9
rthooks: use ContainerID from request
kkourt Aug 7, 2024
ce5a88b
rthooks: introduce Pod()
kkourt Aug 7, 2024
08b6fc9
rthooks: cache cgroupid and pod
kkourt Aug 7, 2024
27df83c
policyfilter: move code into podhelpers package
kkourt Aug 8, 2024
b504409
cgroups: add CgroupIDFromPID
kkourt Aug 9, 2024
679d0ca
rthooks: factor out findPod function in Pod()
kkourt Aug 9, 2024
6f2a10d
rthooks: deal with static pods
kkourt Aug 9, 2024
5d99fd0
policyfilter: move debug code into its own package
kkourt Aug 9, 2024
d6a0cd1
cgidmap: map for improved pod association
kkourt Aug 9, 2024
04229d0
cri: introduce CRI client
kkourt Aug 9, 2024
c302332
tetra: add "cri version" command
kkourt Aug 9, 2024
82d9185
cri: add a function to retrieve the cgroupPath
kkourt Aug 9, 2024
522e8e3
tetra: add "cri cgroup_path" command
kkourt Aug 9, 2024
f459bfe
cgidmap: add CRI resolution
kkourt Aug 9, 2024
8526524
process: resolve pods with cgidmap
kkourt Aug 9, 2024
9b106cd
cgroups: deal with crun subgroups
kkourt Aug 9, 2024
ebd29de
rthooks: use a generic retry function
kkourt Aug 15, 2024
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
83 changes: 83 additions & 0 deletions .github/workflows/tetragon-rthook-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: tetragon-rthooks test
on:
pull_request:
paths:
- 'contrib/tetragon-rthooks/**'
push:
branches:
- main
paths:
- 'contrib/tetragon-rthooks/**'

jobs:
build:
name: Build tetragon-rthooks
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: ${{ github.ref }}-rthooks-build
cancel-in-progress: true
steps:
- name: Checkout code
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
with:
path: go/src/github.com/cilium/tetragon/

- name: Install Go
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
with:
# renovate: datasource=golang-version depName=go
go-version: '1.22.5'

- name: Build
env:
GOPATH: /home/runner/work/tetragon/tetragon/go
run: |
cd go/src/github.com/cilium/tetragon/contrib/tetragon-rthooks
make

- name: tar build
run: |
cd go/src/github.com/cilium/tetragon/contrib
tar cz -f /tmp/tetragon-rthooks.tar ./tetragon-rthooks

- name: upload build
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: tetragon-rthooks-build
path: /tmp/tetragon-rthooks.tar
retention-days: 1
test:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
cri:
- "containerd"
- "crio"
concurrency:
group: ${{ github.ref }}-rthooks-test-${{ matrix.cri }}
cancel-in-progress: true
steps:
- name: start minikube
uses: medyagh/setup-minikube@d8c0eb871f6f455542491d86a574477bd3894533 # v0.0.18
with:
driver: docker
container-runtime: ${{ matrix.cri }}

- name: download build data
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: tetragon-rthooks-build

- name: extract build data
run: |
tar xf tetragon-rthooks.tar

- name: run test
run: |
cd tetragon-rthooks
./scripts/minikube-install-hook.sh -l
./scripts/minikube-test-hook.sh
kkourt marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 8 additions & 0 deletions api/v1/README.md

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

185 changes: 116 additions & 69 deletions api/v1/tetragon/tetragon.pb.go

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions api/v1/tetragon/tetragon.proto
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ message RuntimeHookResponse {}
// This is intented to be used by OCI hooks (but not limited to them) and corresponds to the
// CreateContainer hook:
// https://github.com/opencontainers/runtime-spec/blob/main/config.md#createcontainer-hooks.
//
// The containerName, containerID, podName, podUID, and podNamespace fields are retrieved from the
// annotations as a convenience, and may be left empty if the corresponding annotations are not
// found.
message CreateContainer {
// cgroupsPath is the cgroups path for the container. The path is expected to be relative to the
// cgroups mountpoint. See: https://github.com/opencontainers/runtime-spec/blob/58ec43f9fc39e0db229b653ae98295bfde74aeab/specs-go/config.go#L174
Expand All @@ -652,6 +656,14 @@ message CreateContainer {
map<string, string> annotations = 3;
// containerName is the name of the container
string containerName = 4;
// containerID is the id of the container
string containerID = 5;
// podName is the pod name
string podName = 6;
// podUID is the pod uid
string podUID = 7;
// podNamespace is the namespace of the pod
string podNamespace = 8;
}

message StackTraceEntry {
Expand Down
2 changes: 2 additions & 0 deletions cmd/tetra/commands_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main

import (
"github.com/cilium/tetragon/cmd/tetra/bugtool"
"github.com/cilium/tetragon/cmd/tetra/cri"
"github.com/cilium/tetragon/cmd/tetra/dump"
"github.com/cilium/tetragon/cmd/tetra/loglevel"
"github.com/cilium/tetragon/cmd/tetra/policyfilter"
Expand All @@ -21,4 +22,5 @@ func addCommands(rootCmd *cobra.Command) {
rootCmd.AddCommand(policyfilter.New())
rootCmd.AddCommand(probe.New())
rootCmd.AddCommand(loglevel.New())
rootCmd.AddCommand(cri.New())
}
103 changes: 103 additions & 0 deletions cmd/tetra/cri/cri.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Tetragon

package cri

import (
"context"
"encoding/json"
"fmt"

"github.com/cilium/tetragon/pkg/cri"
"github.com/spf13/cobra"
criapi "k8s.io/cri-api/pkg/apis/runtime/v1"
)

type criFlags struct {
output string
endpoint string
}

func defaultFlags() *criFlags {
return &criFlags{
output: "raw",
endpoint: "",
}
}

func New() *cobra.Command {
flagVals := defaultFlags()
ret := &cobra.Command{
Use: "cri",
Short: "connect to CRI",
Hidden: false,
SilenceUsage: false,
}

ret.AddCommand(
versionCmd(flagVals),
cgroupPathCmd(flagVals),
)

flags := ret.PersistentFlags()
flags.StringVarP(&flagVals.output, "output", "o", flagVals.output, "Output format (raw or json)")
flags.StringVarP(&flagVals.endpoint, "runtime-endpoint", "r", flagVals.endpoint, "CRI endpoint")

return ret
}

func versionCmd(flagVals *criFlags) *cobra.Command {
ret := &cobra.Command{
Use: "version",
Short: "retrieve CRI version",
Args: cobra.ExactArgs(0),
RunE: func(_ *cobra.Command, _ []string) error {
ctx := context.Background()
kkourt marked this conversation as resolved.
Show resolved Hide resolved
client, err := cri.NewClient(ctx, flagVals.endpoint)
if err != nil {
return err
}

res, err := client.Version(ctx, &criapi.VersionRequest{})
if err != nil {
return err
}

switch flagVals.output {
case "raw":
fmt.Printf("%v\n", res)
case "json":
b, err := json.Marshal(res)
if err != nil {
return fmt.Errorf("failed to generate json: %w", err)
}
fmt.Println(string(b))
}
return nil
},
}
return ret
}

func cgroupPathCmd(flagVals *criFlags) *cobra.Command {
ret := &cobra.Command{
Use: "cgroup_path",
Short: "retrieve cgroup path for container",
Args: cobra.ExactArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
ctx := context.Background()
client, err := cri.NewClient(ctx, flagVals.endpoint)
if err != nil {
return err
}

ret, err := cri.CgroupPath(ctx, client, args[0])
if err != nil {
return err
}
fmt.Println(ret)
return nil
},
}
return ret
}
91 changes: 83 additions & 8 deletions contrib/tetragon-rthooks/cmd/oci-hook/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,85 @@ func getCgroupPath(spec *specs.Spec) (string, error) {

func containerNameFromAnnotations(annotations map[string]string) string {
// containerd
// ref: https://github.com/containerd/containerd/blob/7f707b5e7970105723257d483394454049eabe47/internal/cri/annotations/annotations.go#L75-L76
// https://github.com/containerd/containerd/blob/7f707b5e7970105723257d483394454049eabe47/internal/cri/nri/nri_api_linux.go#L721-L723
if val, ok := annotations["io.kubernetes.cri.container-name"]; ok {
return val
}

// crio
// ref: https://github.com/cri-o/cri-o/blob/cd3a03c9f7852227f8171e7698535610e41e2e29/server/nri-api.go#L597-L599
if val, ok := annotations["io.kubernetes.container.name"]; ok {
return val
}

return ""
}

func containerIDFromAnnotations(annotations map[string]string) string {
// crio
// ref: https://github.com/cri-o/cri-o/blob/cd3a03c9f7852227f8171e7698535610e41e2e29/server/nri-api.go#L586-L591
// https://github.com/cri-o/cri-o/blob/5fcc64c8d159e89c040928e4b0032f359a1c864e/pkg/annotations/internal.go#L8
if val, ok := annotations["io.kubernetes.cri-o.ContainerID"]; ok {
return val
}

// NB: containerd does not have the container id in the annotations
return ""
}

func podNameFromAnnotations(annotations map[string]string) string {
// containerd
// ref: https://github.com/containerd/containerd/blob/7f707b5e7970105723257d483394454049eabe47/internal/cri/annotations/annotations.go#L72-L73
if val, ok := annotations["io.kubernetes.cri.sandbox-name"]; ok {
return val
}

// crio
// ref: https://github.com/cri-o/cri-o/blob/cd3a03c9f7852227f8171e7698535610e41e2e29/vendor/k8s.io/kubelet/pkg/types/labels.go#L21
// (not sure how the label ends up in annotations though)
if val, ok := annotations["io.kubernetes.pod.name"]; ok {
return val
}

return ""
}

func podUIDFromAnnotations(annotations map[string]string) string {
// containerd
// ref: https://github.com/containerd/containerd/blob/7f707b5e7970105723257d483394454049eabe47/internal/cri/annotations/annotations.go#L67-L70
if val, ok := annotations["io.kubernetes.cri.sandbox-uid"]; ok {
return val
}

// crio
// ref: https://github.com/cri-o/cri-o/blob/cd3a03c9f7852227f8171e7698535610e41e2e29/vendor/k8s.io/kubelet/pkg/types/labels.go#L23
// (not sure how the label ends up in annotations though)
if val, ok := annotations["io.kubernetes.pod.uid"]; ok {
return val
}

return ""

}

func podNamespaceFromAnnotations(annotations map[string]string) string {
// containerd
// ref: https://github.com/containerd/containerd/blob/7f707b5e7970105723257d483394454049eabe47/internal/cri/annotations/annotations.go#L64-L65
if val, ok := annotations["io.kubernetes.cri.sandbox-namespace"]; ok {
return val
}

// crio
// ref: https://github.com/cri-o/cri-o/blob/cd3a03c9f7852227f8171e7698535610e41e2e29/vendor/k8s.io/kubelet/pkg/types/labels.go#L22
// (not sure how the label ends up in annotations though)
if val, ok := annotations["io.kubernetes.pod.namespace"]; ok {
return val
}

return ""
}

// NB: the second argument is only used in case of an error, so disable revive's complains
// revive:disable:error-return
func createContainerHook(log *slog.Logger) (error, map[string]string) {
Expand Down Expand Up @@ -192,23 +259,31 @@ func createContainerHook(log *slog.Logger) (error, map[string]string) {
return errors.New("unable to determine either RootDir or cgroupPath, bailing out"), nil
}

containerName := containerNameFromAnnotations(spec.Annotations)
createContainer := &tetragon.CreateContainer{
CgroupsPath: cgroupPath,
RootDir: rootDir,
ContainerName: containerNameFromAnnotations(spec.Annotations),
ContainerID: containerIDFromAnnotations(spec.Annotations),
PodName: podNameFromAnnotations(spec.Annotations),
PodUID: podUIDFromAnnotations(spec.Annotations),
PodNamespace: podNamespaceFromAnnotations(spec.Annotations),
Annotations: spec.Annotations,
}

req := &tetragon.RuntimeHookRequest{
Event: &tetragon.RuntimeHookRequest_CreateContainer{
CreateContainer: &tetragon.CreateContainer{
CgroupsPath: cgroupPath,
RootDir: rootDir,
Annotations: spec.Annotations,
ContainerName: containerName,
},
CreateContainer: createContainer,
},
}

log = log.With(
"req-cgroups", cgroupPath,
"req-rootdir", rootDir,
"req-containerName", containerName,
"req-containerName", createContainer.ContainerName,
"req-containerID", createContainer.ContainerID,
"req-podName", createContainer.PodName,
"req-podUID", createContainer.PodUID,
"req-podNamespace", createContainer.PodNamespace,
)
if log.Enabled(context.TODO(), slog.LevelDebug) {
// NB: only add annotations in debug level since they are too noisy
Expand Down
Loading
Loading