Skip to content

Add support for matchWorkloads selector#4833

Open
tpapagian wants to merge 7 commits into
mainfrom
pr/apapag/matchWorkloads
Open

Add support for matchWorkloads selector#4833
tpapagian wants to merge 7 commits into
mainfrom
pr/apapag/matchWorkloads

Conversation

@tpapagian
Copy link
Copy Markdown
Member

@tpapagian tpapagian commented Apr 8, 2026

This works in a similar way to global workload selectors but allows to do fine-grain workload selection inside a single tracing policy.

Example:

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: "file-monitoring-filtered"
spec:
  kprobes:
  - call: "security_file_permission"
    syscall: false
    return: true
    args:
    - index: 0
      type: "file" # (struct file *) used for getting the path
    - index: 1
      type: "int" # 0x04 is MAY_READ, 0x02 is MAY_WRITE
    returnArg:
      index: 0
      type: "int"
    selectors:
    - matchArgs:      
      - index: 0
        operator: "Prefix"
        values:
        - "/etc/shadow"
      - index: 1
        operator: "Equal"
        values:
        - "2" # MAY_WRITE
      matchWorkloads: # match only host workloads
      - hostSelector: {}
    - matchArgs:      
      - index: 0
        operator: "Prefix"
        values:
        - "/etc/shadow"
      - index: 1
        operator: "Equal"
        values:
        - "4" # MAY_READ
      matchWorkloads: # match host workloads and pods inside "kube-system" namespace
      - hostSelector: {}
        podSelector:
          matchExpressions:
          - key: "k8s:io.kubernetes.pod.namespace"
            operator: In
            values:
            - "kube-system"

More details can be found in each patch.

@tpapagian tpapagian changed the title Pr/apapag/match workloads Add support for matchWorkloads selector Apr 8, 2026
@tpapagian tpapagian added the release-note/minor This PR introduces a minor user-visible change label Apr 8, 2026
@tpapagian tpapagian force-pushed the pr/apapag/hostSelector branch 5 times, most recently from a8979e5 to 6db1882 Compare April 16, 2026 07:23
Base automatically changed from pr/apapag/hostSelector to main April 16, 2026 11:34
@tpapagian tpapagian force-pushed the pr/apapag/matchWorkloads branch 3 times, most recently from 754b635 to 76a913b Compare April 17, 2026 14:28
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 20, 2026

Deploy Preview for tetragon ready!

Name Link
🔨 Latest commit 9161377
🔍 Latest deploy log https://app.netlify.com/projects/tetragon/deploys/69fd8e015529e80008869b17
😎 Deploy Preview https://deploy-preview-4833--tetragon.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@tpapagian tpapagian force-pushed the pr/apapag/matchWorkloads branch from 89e5241 to 99a256a Compare April 22, 2026 06:39
@tpapagian tpapagian marked this pull request as ready for review April 22, 2026 08:19
@tpapagian tpapagian requested review from a team and mtardy as code owners April 22, 2026 08:19
@tpapagian tpapagian marked this pull request as draft April 27, 2026 11:15
@tpapagian tpapagian force-pushed the pr/apapag/matchWorkloads branch 3 times, most recently from 0ebb911 to 7541127 Compare April 29, 2026 09:11
@tpapagian tpapagian marked this pull request as ready for review April 29, 2026 10:09
Copy link
Copy Markdown
Member

@mtardy mtardy left a comment

Choose a reason for hiding this comment

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

Thanks!! A few comments, I think it's almost good to go :)

ContainerSelector *slimv1.LabelSelector `json:"containerSelector"`
// +kubebuilder:validation:Optional
// HostSelector selects hosts that this policy applies to.
// For now only ~ (none) and {} (all) is supported.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

note: maybe we can X-Validation that only ~ and {} is supported?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, this make sense, I have added:

// +kubebuilder:validation:XValidation:rule="!has(self.matchLabels) && !has(self.matchExpressions)",message="The hostSelector should be either null or {}."

that seems to work.

I have also created #4947 to add the same validation check in the global spec.hostSelector.

Comment thread pkg/selectors/kernel.go Outdated
// to be {}. This will match everything and for this reason we should not use
// a policyfilter at all.
matchAll := func(s *slimv1.LabelSelector) bool {
return (s != nil && (len(s.MatchLabels)+len(s.MatchExpressions) == 0))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does that work here to compare to an empty LabelSelector? like LabelSelector{}?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Seems to work with DeepEqual. I have changed that as it make the code cleaner.

Comment thread pkg/selectors/kernel.go Outdated
return nil
}

// If the user specifies a podSelector but don't specify a containerSelector,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

small typo: dont -> doesn't. Also in next comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

Comment thread pkg/selectors/kernel.go Outdated

// If the user specifies a podSelector but don't specify a containerSelector,
// we assume that the user cares for all containers inside the pods that match.
if podSelector != nil && containerSelector == nil {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe reuse you matchNothing method here for containerSelector? It's fairly trivial but I think it documents well the code. Same after

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

filterMap := program.MapBuilderProgram("filter_map", load)
maps = append(maps, filterMap)

workloadsMap := program.MapBuilderProgram("workloads_map", load)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe make workloads_map a const somewhere and reference it every time you use it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I would propose to leave it as it is for now because it is not clear to me on where is a good place to add this const. Possibly pkg/selectors/kernel.go but this will not make things consistent as it is now in the previous program.MapBuilderProgram calls in the same file. If you have anything specific in mind, just let me know.


## Workloads filter

Workloads filter can be specified under the `matchWorkloads` field and provide
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

provide -> provides

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed


This works in a similar way to global workload selectors such as `spec.hostSelector`,
`spec.podSelector`, and `spec.containerSelector`. More details on these
can be found in [Filtering semantics](https://tetragon.io/docs/concepts/tracing-policy/k8s-filtering/#filtering-semantics).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

please reference the rest of the docs using relative path, here would be

[Filtering semantics]({{< ref "/docs/concepts/tracing-policy/k8s-filtering/#filtering-semantics" >}})

This allows the doc to know at build time if things still exist more importantly and domain name to be changed (if we rename tetragon lol).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

@tpapagian tpapagian force-pushed the pr/apapag/matchWorkloads branch 7 times, most recently from 6a10f6a to 5401456 Compare May 4, 2026 14:33
@tpapagian tpapagian force-pushed the pr/apapag/matchWorkloads branch from 5401456 to 34dd182 Compare May 4, 2026 14:42
@tpapagian
Copy link
Copy Markdown
Member Author

Thanks!! A few comments, I think it's almost good to go :)

Thanks for the review. I believe I have addressed all of your comments.

@tpapagian tpapagian requested a review from mtardy May 4, 2026 15:42
@kkourt kkourt self-requested a review May 5, 2026 07:06
Copy link
Copy Markdown
Member

@mtardy mtardy left a comment

Choose a reason for hiding this comment

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

Cool thanks!

@tpapagian tpapagian force-pushed the pr/apapag/matchWorkloads branch from 34dd182 to 9161377 Compare May 8, 2026 07:17
tpapagian added 7 commits May 8, 2026 10:19
Example:
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: "file-monitoring-filtered"
spec:
  kprobes:
  - call: "security_file_permission"
    syscall: false
    return: true
    args:
    - index: 0
      type: "file" # (struct file *) used for getting the path
    - index: 1
      type: "int" # 0x04 is MAY_READ, 0x02 is MAY_WRITE
    returnArg:
      index: 0
      type: "int"
    selectors:
    - matchArgs:
      - index: 0
        operator: "Prefix"
        values:
        - "/etc/shadow"
      - index: 1
        operator: "Equal"
        values:
        - "2" # MAY_WRITE
      matchWorkloads: # match only host workloads
      - hostSelector: {}
    - matchArgs:
      - index: 0
        operator: "Prefix"
        values:
        - "/etc/shadow"
      - index: 1
        operator: "Equal"
        values:
        - "4" # MAY_READ
      matchWorkloads: # match host workloads and pods inside "kube-system" namespace
      - hostSelector: {}
        podSelector:
          matchExpressions:
          - key: "k8s:io.kubernetes.pod.namespace"
            operator: In
            values:
            - "kube-system"

This will allow us to do fine-grain workload selection inside a single
tracing polity.

Signed-off-by: Anastasios Papagiannis <anastasios.papagiannis@isovalent.com>
Signed-off-by: Anastasios Papagiannis <anastasios.papagiannis@isovalent.com>
We expect to have a map named workloads_map that have pairs of selector
IDs and policy IDs. Then we reuse the policy_filter_check function to
check if the policy is applied to a specific selector.

In next patches, the agent will populate the workloads_map. The idea is
to reuse the existing infra that we have inside policyfilter and is used
in global selectors.

Signed-off-by: Anastasios Papagiannis <anastasios.papagiannis@isovalent.com>
Will be used in the next patch.

Signed-off-by: Anastasios Papagiannis <anastasios.papagiannis@isovalent.com>
In order to achieve that we reuse the existing support for global
selectors inside policyfilter.

For each selector that has a matchWorkloads filter, we allocate a new
policy ID. In order not to collide with global policy IDs we start to
allocate IDs after the range of IDs for global selectors.

Based on that we assume that each matchWorkloads selector is a global
selector and we call AddPolicy with the selector.

We also take care of deallocating all of those when a policy is removed.

Signed-off-by: Anastasios Papagiannis <anastasios.papagiannis@isovalent.com>
Signed-off-by: Anastasios Papagiannis <anastasios.papagiannis@isovalent.com>
Signed-off-by: Anastasios Papagiannis <anastasios.papagiannis@isovalent.com>
@tpapagian tpapagian force-pushed the pr/apapag/matchWorkloads branch from 9161377 to 23f20b1 Compare May 8, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/minor This PR introduces a minor user-visible change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants