Skip to content

allow network-slices to be a cel selector for internal/external traffic - #902

Draft
entlein wants to merge 1 commit into
kubescape:mainfrom
k8sstormcenter:upstream-pr/celnetworkselector
Draft

allow network-slices to be a cel selector for internal/external traffic#902
entlein wants to merge 1 commit into
kubescape:mainfrom
k8sstormcenter:upstream-pr/celnetworkselector

Conversation

@entlein

@entlein entlein commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

The use-case I wrote this for is to allow-list a client esp for cluster interal traffic using the well-known network-policy like selectors.

I also suggest to symmterizice the rules, to have them for internal and external traffic and both egress and ingress (seperate as the threat-model is different).

Example can be found here k8sstormcenter/bob#187

Watch R0012 on valkey-primary's node

MNODE=$(kubectl -n valkey get pod valkey-primary-0 -o jsonpath='{.spec.nodeName}')
NA=$(kubectl -n honey get pod -o wide --field-selector spec.nodeName=$MNODE --no-headers | awk '/node-agent/{print $1;exit}')
kubectl -n honey logs -f $NA | grep "Unexpected ingress network"

Deploy the client without matching the labes — R0012 fires:

kubectl apply -f valkey-client.yaml

Allowlist that identity — R0012 stops:

kubectl -n valkey patch $CP valkey --type merge -p '{"spec":{"ingress":[{"type":"internal","podSelector":{"matchLabels":{"app":"valkey-client"}},"namespaceSelector":{"matchLabels":{"kubernetes.io/metadata.name":"valkey"}},"ports":[{"name":"TCP-6379","port":6379,"protocol":"TCP"}]}]}}'

Why I think we should have this

Cause excluding traffic in the profiles, based on IP is impossible (changing IPs) . This works for external static IPs or ranges.
Thus, if we wish to alert if internal connections are happening that we didnt intend, we need to match something predictable and static.
The NWP syntax is well-established

TODO

I need to test this again after the large rebase, cause previous bugs where that the inter-cluster (across several nodes) traffic wasnt getting properly attributed.
If they got lost, this needs tests to check for

  • same node-traffic (int/ext)
  • internode traffic (int/ext)

Needs a followup PR in rulelibrary

…c allowlisting

Signed-off-by: entlein <einentlein@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 69d66cf2-da31-4c8c-b893-caea2856a4c7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@entlein entlein changed the title allow networkpolicy to be a cel selector for internal/external traffic allow network-slices to be a cel selector for internal/external traffic Aug 18, 2026

@matthyx matthyx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the diff and checked it out locally (go build ./..., go test ./pkg/objectcache/containerprofilecache/... ./pkg/rulemanager/cel/... — all pass; gofmt -l clean on the changed files).

No blockers found in the code itself. A few notes:

  • Verified namespaceSelectorMatches's "nil selector ⇒ same namespace as the profiled workload" rule against the actual generator (pkg/containerprofilemanager/v1/container_data.go createNetworkNeighbor/getNamespaceMatchLabels): the generator only omits NamespaceSelector when destinationNamespace == sourceNamespace, and always sets PodSelector alongside any NamespaceSelector for Pod/Service kinds — so extractPeers's PodSelector != nil gate won't silently drop any entry the current generator actually produces. Good match between the CEL-side semantics and the write-side encoding.
  • Confirmed L3Endpoint.Namespace/PodLabels really are populated cluster-wide by IG's KubeIPResolver operator (not node-local), which backs the PR's cross-node design claim.
  • was_selector_in_{ingress,egress} correctly reuses the existing ConvertProfileNotAvailableErrToBool error path and cost-estimator pattern used by the other cp.* helpers; the noCache bypass is reasonable since the map arg has no stable cache key.
  • Minor/non-blocking: extractPeers drops any neighbor entry with only a NamespaceSelector and no PodSelector. The current learned-profile generator never emits that shape, but if a hand-authored/edited ContainerProfile ever did (valid per NetworkPolicyPeer semantics — namespaceSelector alone = "all pods in matching namespaces"), it would silently never match. Not worth blocking on given today's only producer, but maybe worth a one-line comment or a follow-up if user-edited profiles become a supported path.

Holding off on approval since this PR is still a draft and the description itself flags it as not merge-ready yet — the author's own TODO calls for re-testing after the rebase specifically for same-node vs. inter-node (cross-node) attribution, int/ext, which isn't covered by the new unit tests here (those exercise the CEL/projection logic against fixed inputs, not the live IG resolver path across nodes). The companion rule-library wiring (R0012 in default-rules.yaml) is also intentionally not part of this PR. Happy to take another pass and approve once it's marked ready for review and the rebase re-test is done.

@matthyx matthyx moved this to Waiting on Author in KS PRs tracking Aug 19, 2026
@entlein

entlein commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author
  • Minor/non-blocking: extractPeers drops any neighbor entry with only a NamespaceSelector and no PodSelector. The current learned-profile generator never emits that shape, but if a hand-authored/edited ContainerProfile ever did (valid per NetworkPolicyPeer semantics — namespaceSelector alone = "all pods in matching namespaces"), it would silently never match. Not worth blocking on given today's only producer, but maybe worth a one-line comment or a follow-up if user-edited profiles become a supported path.

Good point and here's my two cents:
Given that we argued that for user-defined-profiles, we'd leave the namespace open in general (cause a vendor doesnt know which ns an app/client/thingy gets deployed into), I dont consider it consistent to match for ONLY NamespaceSelector.

On the contrary:

  • matching only the PodSelector would be consistent with how the narrative currently flows (also the up-coming signature PR)
  • I would keep NamespaceSelector for both performance and uniqueness reasons , also possibly because it could be confusing otherwise.

From a threat-model PoV: I see is little advantage to match only on NamespaceSelector, as (a vanilla k8s) doesnt restrict how many objects there are potentially in one namespace, so allowlisting everything in there carte blanche, could create a false sense of security.

Reason both of these Rule PRs are in draft is so we have time to test it on IRL usecases for exactly those rationales and weigh UX vs number of false-positives when user does it wrong vs how its easiest to get it right.

If anyone (at all out there), has IRL examples that lean to either or, please do comment ☺️♥️

@matthyx matthyx moved this from Waiting on Author to Needs Reviewer in KS PRs tracking Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Needs Reviewer

Development

Successfully merging this pull request may close these issues.

2 participants