Skip to content

Commit

Permalink
feat: add containerSelector to the policy filter
Browse files Browse the repository at this point in the history
When running Tetragon in Kubernetes, it's possible to filter pods that
the policy will be applied to by pod labels and namespaces.
This change adds support for filtering by the container name inside the
pod or potentially a different field in the future.

The filtering happens in the "containerMatches" method. We construct a
map of key value pairs that represent different fields in the container.
Then, we apply the same label filtering as in the "podMatches" method.
At the moment, only the "name" field is supported.

Since we are dealing with multiple containers inside a pod and we only
need their cgroup ids to add to the policyfilter map, the "matchingContainersCgroupIDs"
method was added. It iterates over a slice of containers, finds matching
containers using "containerMatches", and returns their cgroup ids. This method is used for
all operations where we need to change cgroup ids in the policyfilter
map including applying policy diff, adding a new policy, etc.

This patch makes the following changes:

1. Adds the containerSelector field to the policyfilter package.
2. Updates CRD schema for tracing policies with containerSelector.
3. Bumps the CRD version.

Fixes: cilium#1879

Signed-off-by: Oleh Neichev <[email protected]>
  • Loading branch information
BonySmoke committed Apr 6, 2024
1 parent bd63a46 commit f459386
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 61 deletions.
7 changes: 7 additions & 0 deletions pkg/k8s/apis/cilium.io/v1alpha1/tracing_policy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ type TracingPolicySpec struct {
// PodSelector selects pods that this policy applies to
PodSelector *slimv1.LabelSelector `json:"podSelector,omitempty"`

// +kubebuilder:validation:Optional
// ContainerSelector selects containers that this policy applies to.
// A map of container fields will be constructed in the same way as a map of labels.
// The name of the field represents the label "key", and the value of the field - label "value".
// Currently, only the "name" field is supported.
ContainerSelector *slimv1.LabelSelector `json:"containerSelector,omitempty"`

// +kubebuilder:validation:Optional
// A list of list specs.
Lists []ListSpec `json:"lists,omitempty"`
Expand Down
9 changes: 6 additions & 3 deletions pkg/policyfilter/disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ func DisabledState() State {
type disabled struct {
}

func (s *disabled) AddPolicy(polID PolicyID, namespace string, podSelector *slimv1.LabelSelector) error {
func (s *disabled) AddPolicy(polID PolicyID, namespace string, podSelector *slimv1.LabelSelector,
containerSelector *slimv1.LabelSelector) error {
return fmt.Errorf("policyfilter is disabled")
}

Expand All @@ -30,11 +31,13 @@ func (s *disabled) DelPolicy(polID PolicyID) error {
return fmt.Errorf("policyfilter is disabled")
}

func (s *disabled) AddPodContainer(podID PodID, namespace string, podLabels labels.Labels, containerID string, cgIDp CgroupID) error {
func (s *disabled) AddPodContainer(podID PodID, namespace string, podLabels labels.Labels,
containerID string, cgID CgroupID, containerName string) error {
return nil
}

func (s *disabled) UpdatePod(podID PodID, namespace string, podLabels labels.Labels, containerIDs []string) error {
func (s *disabled) UpdatePod(podID PodID, namespace string, podLabels labels.Labels,
containerIDs []string, containerNames []string) error {
return nil
}

Expand Down
8 changes: 8 additions & 0 deletions pkg/policyfilter/podhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,11 @@ func podContainersIDs(pod *v1.Pod) []string {
})
return ret
}

func podContainersNames(pod *v1.Pod) []string {
ret := make([]string, 0)
podForAllContainers(pod, func(c *v1.ContainerStatus) {
ret = append(ret, c.Name)
})
return ret
}
10 changes: 7 additions & 3 deletions pkg/policyfilter/policyfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,23 @@ type State interface {
// pods are matched with:
// - namespace for namespaced pilicies (if namespace == "", then policy is not namespaced)
// - label selector
AddPolicy(polID PolicyID, namespace string, podSelector *slimv1.LabelSelector) error
// - container field selector
AddPolicy(polID PolicyID, namespace string, podSelector *slimv1.LabelSelector,
containerSelector *slimv1.LabelSelector) error

// DelPolicy removes a policy from the state
DelPolicy(polID PolicyID) error

// AddPodContainer informs policyfilter about a new container and its cgroup id in a pod.
// The pod might or might not have been encountered before.
// This method is intended to update policyfilter state from container hooks
AddPodContainer(podID PodID, namespace string, podLabels labels.Labels, containerID string, cgID CgroupID) error
AddPodContainer(podID PodID, namespace string, podLabels labels.Labels,
containerID string, cgID CgroupID, containerName string) error

// UpdatePod updates the pod state for a pod, where containerIDs contains all the container ids for the given pod.
// This method is intended to be used from k8s watchers (where no cgroup information is available)
UpdatePod(podID PodID, namespace string, podLabels labels.Labels, containerIDs []string) error
UpdatePod(podID PodID, namespace string, podLabels labels.Labels,
containerIDs []string, containerNames []string) error

// DelPodContainer informs policyfilter that a container was deleted from a pod
DelPodContainer(podID PodID, containerID string) error
Expand Down
20 changes: 15 additions & 5 deletions pkg/policyfilter/rthooks/rthooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,25 @@ func createContainerHook(_ context.Context, arg *rthooks.CreateContainerArg) err
return err
}

var containerFound bool
var container *corev1.ContainerStatus
namespace := pod.ObjectMeta.Namespace
pod, container, containerFound = arg.Watcher.FindContainer(containerID)
if !containerFound {
log.WithError(err).Warnf("failed to find container information %s, aborting hook.", containerID)
}

containerName := container.Name

log.WithFields(logrus.Fields{
"pod-id": podID,
"namespace": namespace,
"container-id": containerID,
"cgroup-id": cgID,
"pod-id": podID,
"namespace": namespace,
"container-id": containerID,
"cgroup-id": cgID,
"container-name": containerName,
}).Trace("policyfilter: add pod container")
cgid := policyfilter.CgroupID(cgID)
if err := pfState.AddPodContainer(policyfilter.PodID(podID), namespace, pod.Labels, containerID, cgid); err != nil {
if err := pfState.AddPodContainer(policyfilter.PodID(podID), namespace, pod.Labels, containerID, cgid, containerName); err != nil {
log.WithError(err).Warn("failed to update policy filter, aborting hook.")
}
policyfiltermetrics.OpInc(policyfiltermetrics.RTHooksSubsys, policyfiltermetrics.AddContainerOperation, policyfilter.ErrorLabel(err))
Expand Down
Loading

0 comments on commit f459386

Please sign in to comment.