feat: Add quota handling via NPE#2593
Conversation
6abc7f6 to
065d8c3
Compare
7d42685 to
70b075c
Compare
b07a10c to
cb52b93
Compare
ef64989 to
cd61fd6
Compare
bbc7e19 to
a80e11f
Compare
|
nsp test is failing in ci-test-ginkgo with some policy validation issue, can you please check |
|
@Aryan-sharma11 I tested these scenarios 1. Pod level quota ✅Created a nginx deployment with 3 replicas Tested pod level network quota with following policy apiVersion: security.kubearmor.com/v1
kind: KubeArmorNetworkPolicy
metadata:
name: nsp-quota-pod-nginx
spec:
selector:
matchLabels:
app: nginx
action: Block
level: Pod
ingress:
- limit: "1KB"
duration: "20m"Received the expected alert for each pod, and network got blocked afterwards $ ./karmor logs --gRPC :32767
Created a gRPC client (:32767)
Checked the liveness of the gRPC server
Started to watch alerts
== Alert / 2026-06-04 11:53:05.441994 ==
ClusterName: default
HostName: ubuntu
NamespaceName: default
PodName: nginx-deployment-59f86b59ff-mm5b5
Labels: app=nginx
Type: MatchedNetworkPolicy
PolicyName: nsp-quota-pod-nginx
Resource: INGRESS
Operation: NetworkFirewall
Action: Block
Data: SourceIP=8.8.8.8 SourcePort=0 DestinationIP=10.42.0.37 DestinationPort=0 Protocol=ICMP QuotaLevel=pod QuotaLimit=1KB
EventData: map[DestinationIP:10.42.0.37 DestinationPort:0 Protocol:ICMP QuotaLevel:pod QuotaLimit:1KB SourceIP:8.8.8.8 SourcePort:0]
Enforcer: NetworkPolicyEnforcer
Result: Permission denied
ExecEvent: map[]
PPID: 0
UID: 0
== Alert / 2026-06-04 11:53:54.210777 ==
ClusterName: default
HostName: ubuntu
NamespaceName: default
PodName: nginx-deployment-59f86b59ff-vc44n
Labels: app=nginx
Type: MatchedNetworkPolicy
PolicyName: nsp-quota-pod-nginx
Resource: INGRESS
Operation: NetworkFirewall
Action: Block
Data: SourceIP=8.8.8.8 SourcePort=0 DestinationIP=10.42.0.38 DestinationPort=0 Protocol=ICMP QuotaLevel=pod QuotaLimit=1KB
EventData: map[DestinationIP:10.42.0.38 DestinationPort:0 Protocol:ICMP QuotaLevel:pod QuotaLimit:1KB SourceIP:8.8.8.8 SourcePort:0]
Enforcer: NetworkPolicyEnforcer
Result: Permission denied
ExecEvent: map[]
PPID: 0
UID: 0
== Alert / 2026-06-04 11:54:26.721846 ==
ClusterName: default
HostName: ubuntu
NamespaceName: default
PodName: nginx-deployment-59f86b59ff-sk87x
Labels: app=nginx
Type: MatchedNetworkPolicy
PolicyName: nsp-quota-pod-nginx
Resource: INGRESS
Operation: NetworkFirewall
Action: Block
Data: SourceIP=8.8.8.8 SourcePort=0 DestinationIP=10.42.0.36 DestinationPort=0 Protocol=ICMP QuotaLevel=pod QuotaLimit=1KB
EventData: map[DestinationIP:10.42.0.36 DestinationPort:0 Protocol:ICMP QuotaLevel:pod QuotaLimit:1KB SourceIP:8.8.8.8 SourcePort:0]
Enforcer: NetworkPolicyEnforcer
Result: Permission denied
ExecEvent: map[]
PPID: 0
UID: 02. Policy level quota ✅With the same nginx deployment havign 3 replicas
Tested pod level network quota with following policy apiVersion: security.kubearmor.com/v1
kind: KubeArmorNetworkPolicy
metadata:
name: nsp-quota-pod-nginx
spec:
selector:
matchLabels:
app: nginx
action: Block
level: Policy
ingress:
- limit: "1KB"
duration: "20m"Got the alert, with network blocked for all 3 pods $ ./karmor logs --gRPC :32767
Created a gRPC client (:32767)
Checked the liveness of the gRPC server
Started to watch alerts
== Alert / 2026-06-04 13:30:40.183343 ==
ClusterName: default
HostName: ubuntu
NamespaceName: default
PodName: nginx-deployment-59f86b59ff-sk87x
Labels: app=nginx
Type: MatchedNetworkPolicy
PolicyName: nsp-quota-pod-nginx
Resource: INGRESS
Operation: NetworkFirewall
Action: Block
Data: SourceIP=8.8.8.8 SourcePort=0 DestinationIP=10.42.0.36 DestinationPort=0 Protocol=ICMP QuotaLevel=policy QuotaLimit=1KB
EventData: map[DestinationIP:10.42.0.36 DestinationPort:0 Protocol:ICMP QuotaLevel:policy QuotaLimit:1KB SourceIP:8.8.8.8 SourcePort:0]
Enforcer: NetworkPolicyEnforcer
Result: Permission denied
ExecEvent: map[]
NodeID: ab58f2d4e6794592afd5e8d2312ad6e9
PPID: 0
UID: 03. Host quota (Audit) ✅On Ubuntu 24.04 LTS machine,
With host policy apiVersion: security.kubearmor.com/v1
kind: KubeArmorNetworkPolicy
metadata:
name: nsp-quota-host
spec:
nodeSelector:
matchLabels:
kubernetes.io/hostname: ubuntu
action: Audit
ingress:
- limit: "5M"
duration: "20m"Got expected alert $ ./karmor logs --gRPC :32767
Created a gRPC client (:32767)
Checked the liveness of the gRPC server
Started to watch alerts
== Alert / 2026-06-04 13:36:52.698707 ==
ClusterName: default
HostName: ubuntu
Type: MatchedNetworkPolicy
PolicyName: nsp-quota-host
Resource: INGRESS
Operation: NetworkFirewall
Action: Audit
Data: SourceIP=2600:9000:2656:4e00:9:4855:aac0:93a1 SourcePort=443 DestinationIP=2405:201:5c00:68da:46e5:9e2a:c8a0:53be DestinationPort=38856 Protocol=TCP QuotaLimit=5M
EventData: map[DestinationIP:2405:201:5c00:68da:46e5:9e2a:c8a0:53be DestinationPort:38856 Protocol:TCP QuotaLimit:5M SourceIP:2600:9000:2656:4e00:9:4855:aac0:93a1 SourcePort:443]
Enforcer: NetworkPolicyEnforcer
Result: Passed
ExecEvent: map[]
PPID: 0
UID: 04. Host quota (Block) ❌On Ubuntu 24.04 LTS machine
With host policy apiVersion: security.kubearmor.com/v1
kind: KubeArmorNetworkPolicy
metadata:
name: nsp-quota-host
spec:
nodeSelector:
matchLabels:
kubernetes.io/hostname: ubuntu
action: Block
ingress:
- limit: "1M"
duration: "20m"Did not get the alert because all connections (including kubearmor-karmor, kubearmor-k8s, kubearmor-CRI) were broken. This needs to be discussed, and if this is a limitation then it needs to be documented well 5. Host quota + CIDR, Port policy ❌On Ubuntu 24.04 LTS machine
Using following policy apiVersion: security.kubearmor.com/v1
kind: KubeArmorNetworkPolicy
metadata:
name: nsp-egress-block-dns
spec:
nodeSelector:
matchLabels:
kubernetes.io/hostname: "ubuntu"
egress:
- limit: "1M"
duration: "20m"
- to:
- ipBlock:
cidr: "8.8.8.8/32"
ports:
- port: "dns"
protocol: "UDP"
severity: 5
action: AuditExpected 2 but got only 1 alert $ ./karmor logs --gRPC :32767
Created a gRPC client (:32767)
Checked the liveness of the gRPC server
Started to watch alerts
== Alert / 2026-06-04 13:50:50.294545 ==
ClusterName: default
HostName: ubuntu
Type: MatchedNetworkPolicy
PolicyName: nsp-egress-block-dns
Severity: 5
Resource: EGRESS
Operation: NetworkFirewall
Action: Audit
Data: SourceIP=2405:201:5c00:68da:46e5:9e2a:c8a0:53be SourcePort=46983 DestinationIP=2405:201:5c00:68da::c0a8:1d01 DestinationPort=53 Protocol=UDP
EventData: map[DestinationIP:2405:201:5c00:68da::c0a8:1d01 DestinationPort:53 Protocol:UDP SourceIP:2405:201:5c00:68da:46e5:9e2a:c8a0:53be SourcePort:46983]
Enforcer: NetworkPolicyEnforcer
Result: Passed
ExecEvent: map[]
PPID: 0
UID: 0 |
5247d23 to
1675b2d
Compare
1675b2d to
60e395f
Compare
73446a5 to
440ee77
Compare
89ddd2d to
a7067d1
Compare
There was a problem hiding this comment.
@Aryan-sharma11 I tested with this policy again
apiVersion: security.kubearmor.com/v1
kind: KubeArmorNetworkPolicy
metadata:
name: nsp-egress-block-dns
spec:
nodeSelector:
matchLabels:
kubernetes.io/hostname: "ubuntu"
egress:
- limit: "1M"
duration: "20m"
- to:
- ipBlock:
cidr: "8.8.8.8/32"
ports:
- port: "dns"
protocol: "UDP"
severity: 5
action: Auditand got the expected 2 alerts ✅
== Alert / 2026-07-01 04:21:02.676996 ==
ClusterName: default
HostName: kubearmor-dev-next
Type: MatchedNetworkPolicy
PolicyName: nsp-cidr-limit
Severity: 5
Resource: EGRESS
Operation: NetworkFirewall
Action: Audit
Data: SourceIP=10.0.2.15 SourcePort=50376 DestinationIP=18.154.206.69 DestinationPort=443 Protocol=TCP QuotaLimit=host
EventData: map[DestinationIP:18.154.206.69 DestinationPort:443 Protocol:TCP QuotaLimit:host SourceIP:10.0.2.15 SourcePort:50376]
Enforcer: NetworkPolicyEnforcer
Result: Passed
ExecEvent: map[]
PPID: 0
UID: 0
UserName: root
== Alert / 2026-07-01 04:22:49.416128 ==
ClusterName: default
HostName: kubearmor-dev-next
Type: MatchedNetworkPolicy
PolicyName: nsp-cidr-limit
Severity: 5
Resource: EGRESS
Operation: NetworkFirewall
Action: Audit
Data: SourceIP=10.0.2.15 SourcePort=40661 DestinationIP=8.8.8.8 DestinationPort=53 Protocol=UDP QuotaLimit=host
EventData: map[DestinationIP:8.8.8.8 DestinationPort:53 Protocol:UDP QuotaLimit:host SourceIP:10.0.2.15 SourcePort:40661]
Enforcer: NetworkPolicyEnforcer
Result: Passed
ExecEvent: map[]
PPID: 0
UID: 0
UserName: root
why we have QuotaLimit=host and not QuotaLimit=20M in quota alert ?
CIDR alert also has QuotaLimit=host
Same behavior with policy having only quota rules
a7067d1 to
8500ccb
Compare
AryanBakliwal
left a comment
There was a problem hiding this comment.
Correct alerts received ✅
== Alert / 2026-07-01 06:58:48.532683 ==
ClusterName: default
HostName: kubearmor-dev-next
Type: MatchedNetworkPolicy
PolicyName: nsp-cidr-limit
Severity: 5
Resource: EGRESS
Operation: NetworkFirewall
Action: Audit
Data: SourceIP=10.0.2.15 SourcePort=52695 DestinationIP=8.8.8.8 DestinationPort=53 Protocol=UDP
EventData: map[DestinationIP:8.8.8.8 DestinationPort:53 Protocol:UDP SourceIP:10.0.2.15 SourcePort:52695]
Enforcer: NetworkPolicyEnforcer
Result: Passed
ExecEvent: map[]
NodeID: bf5cc365450545fcbbbda42e4623a367
PPID: 0
UID: 0
UserName: root
== Alert / 2026-07-01 07:00:01.172655 ==
ClusterName: default
HostName: kubearmor-dev-next
Type: MatchedNetworkPolicy
PolicyName: nsp-cidr-limit
Severity: 5
Resource: EGRESS
Operation: NetworkFirewall
Action: Audit
Data: SourceIP=10.0.2.15 SourcePort=48204 DestinationIP=44.205.212.179 DestinationPort=443 Protocol=TCP QuotaLevel=host QuotaLimit=1M
EventData: map[DestinationIP:44.205.212.179 DestinationPort:443 Protocol:TCP QuotaLevel:host QuotaLimit:1M SourceIP:10.0.2.15 SourcePort:48204]
Enforcer: NetworkPolicyEnforcer
Result: Passed
ExecEvent: map[]
PPID: 0
UID: 0
UserName: root
8500ccb to
25218b9
Compare
Signed-off-by: Aryan-sharma11 <[email protected]>
Signed-off-by: Aryan-sharma11 <[email protected]>
Signed-off-by: Aryan-sharma11 <[email protected]>
Signed-off-by: Aryan-sharma11 <[email protected]>
Signed-off-by: Aryan-sharma11 <[email protected]>
25218b9 to
1736c4b
Compare





Purpose of PR?:
Fixes #2164
Does this PR introduce a breaking change?
If the changes in this PR are manually verified, list down the scenarios covered::
Additional information for reviewer? :
Mention if this PR is part of any design or a continuation of previous PRs
Checklist:
<type>(<scope>): <subject>