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

policyfilter: Apply Policy Only to Specific Containers in a Pod #2231

Merged
merged 8 commits into from
Apr 9, 2024
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"`
kkourt marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

@lambdanis lambdanis Apr 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was confused at first by LabelSelector, as there are no labels involved, but I guess by reusing it we get MatchExpressions in addition to exact name match essentially for free? This seems like a good enough reason to reuse LabelSelector, just checking my understanding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review!

I see there is a conflict in rthooks, hopefully not painful. Could you rebase and resolve it?

Sure, it was caused by the addition of the error label to the policyfilter_metrics_total label. I resolved it:)


I was confused at first by LabelSelector, as there are no labels involved, but I guess by reusing it we get MatchExpressions in addition to exact name match essentially for free?

You are totally right! I imagined container fields the same as labels (a map of key-value pairs) and therefore decided to reuse the existing filtering logic. As you said, essentially for free 😅


// +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)
kkourt marked this conversation as resolved.
Show resolved Hide resolved
}

containerName := container.Name
kkourt marked this conversation as resolved.
Show resolved Hide resolved

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