Skip to content

Commit bd9383d

Browse files
committed
Separating the new functionality to a new control
Signed-off-by: Ben <[email protected]>
1 parent 0b49428 commit bd9383d

File tree

9 files changed

+170
-62
lines changed

9 files changed

+170
-62
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "Exposure to internet via Gateway API",
3+
"attributes": {
4+
"controlTypeTags": [
5+
"security"
6+
],
7+
"attackTracks": [
8+
{
9+
"attackTrack": "workload-external-track",
10+
"categories": [
11+
"Initial Access"
12+
]
13+
},
14+
{
15+
"attackTrack": "service-destruction",
16+
"categories": [
17+
"Initial Access"
18+
]
19+
}
20+
]
21+
},
22+
"description": "This control detect workloads that are exposed on Internet through a Gateway API (HTTPRoute,TCPRoute, UDPRoute). It fails in case it find workloads connected with these resources.",
23+
"remediation": "The user can evaluate its exposed resources and apply relevant changes wherever needed.",
24+
"rulesNames": ["exposure-to-internet-via-gateway-api"],
25+
"test": "Checks if workloads are exposed through the use of Gateway API (HTTPRoute, TCPRoute, UDPRoute).",
26+
"controlID": "C-0266",
27+
"baseScore": 7.0,
28+
"scanningScope": {
29+
"matches": [
30+
"cluster"
31+
]
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package armo_builtins
2+
3+
4+
deny[msga] {
5+
httproute := input[_]
6+
httproute.kind == "HTTPRoute"
7+
8+
svc := input[_]
9+
svc.kind == "Service"
10+
11+
# Make sure that they belong to the same namespace
12+
svc.metadata.namespace == httproute.metadata.namespace
13+
14+
# avoid duplicate alerts
15+
# if service is already exposed through NodePort or LoadBalancer workload will fail on that
16+
not is_exposed_service(svc)
17+
18+
wl := input[_]
19+
wl.metadata.namespace == svc.metadata.namespace
20+
spec_template_spec_patterns := {"Deployment", "ReplicaSet", "DaemonSet", "StatefulSet", "Pod", "Job", "CronJob"}
21+
spec_template_spec_patterns[wl.kind]
22+
wl_connected_to_service(wl, svc)
23+
24+
result := svc_connected_to_httproute(svc, httproute)
25+
26+
msga := {
27+
"alertMessage": sprintf("workload '%v' is exposed through httproute '%v'", [wl.metadata.name, httproute.metadata.name]),
28+
"packagename": "armo_builtins",
29+
"failedPaths": [],
30+
"fixPaths": [],
31+
"alertScore": 7,
32+
"alertObject": {
33+
"k8sApiObjects": [wl]
34+
},
35+
"relatedObjects": [
36+
{
37+
"object": httproute,
38+
"reviewPaths": result,
39+
"failedPaths": result,
40+
},
41+
{
42+
"object": svc,
43+
}
44+
]
45+
}
46+
}
47+
48+
# ====================================================================================
49+
50+
is_exposed_service(svc) {
51+
svc.spec.type == "NodePort"
52+
}
53+
54+
is_exposed_service(svc) {
55+
svc.spec.type == "LoadBalancer"
56+
}
57+
58+
wl_connected_to_service(wl, svc) {
59+
count({x | svc.spec.selector[x] == wl.metadata.labels[x]}) == count(svc.spec.selector)
60+
}
61+
62+
wl_connected_to_service(wl, svc) {
63+
wl.spec.selector.matchLabels == svc.spec.selector
64+
}
65+
66+
wl_connected_to_service(wl, svc) {
67+
count({x | svc.spec.selector[x] == wl.spec.template.metadata.labels[x]}) == count(svc.spec.selector)
68+
}
69+
70+
svc_connected_to_httproute(svc, httproute) = result {
71+
rule := httproute.spec.rules[i]
72+
ref := rule.backendRefs[j]
73+
ref.kind == "Service"
74+
svc.metadata.name == ref.name
75+
result := [sprintf("spec.rules[%d].backendRefs[%d].name", [i,j])]
76+
}
77+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"name": "exposure-to-internet-via-gateway-api",
3+
"attributes": {
4+
},
5+
"ruleLanguage": "Rego",
6+
"match": [
7+
{
8+
"apiGroups": [
9+
""
10+
],
11+
"apiVersions": [
12+
"v1"
13+
],
14+
"resources": [
15+
"Pod",
16+
"Service"
17+
]
18+
},
19+
{
20+
"apiGroups": [
21+
"apps"
22+
],
23+
"apiVersions": [
24+
"v1"
25+
],
26+
"resources": [
27+
"Deployment",
28+
"ReplicaSet",
29+
"DaemonSet",
30+
"StatefulSet"
31+
]
32+
},
33+
{
34+
"apiGroups": [
35+
"batch"
36+
],
37+
"apiVersions": [
38+
"*"
39+
],
40+
"resources": [
41+
"Job",
42+
"CronJob"
43+
]
44+
},
45+
{
46+
"apiGroups": [
47+
"gateway.networking.k8s.io"
48+
],
49+
"apiVersions": [
50+
"v1"
51+
],
52+
"resources": [
53+
"HTTPRoute"
54+
]
55+
}
56+
],
57+
"description": "fails in case the running workload has binded Service and Gateway that are exposing it on Internet.",
58+
"remediation": "",
59+
"ruleQuery": "armo_builtins"
60+
}

rules/exposure-to-internet/raw.rego

-51
Original file line numberDiff line numberDiff line change
@@ -72,50 +72,6 @@ deny[msga] {
7272
}
7373
}
7474

75-
deny[msga] {
76-
httproute := input[_]
77-
httproute.kind == "HTTPRoute"
78-
79-
svc := input[_]
80-
svc.kind == "Service"
81-
82-
# Make sure that they belong to the same namespace
83-
svc.metadata.namespace == httproute.metadata.namespace
84-
85-
# avoid duplicate alerts
86-
# if service is already exposed through NodePort or LoadBalancer workload will fail on that
87-
not is_exposed_service(svc)
88-
89-
wl := input[_]
90-
wl.metadata.namespace == svc.metadata.namespace
91-
spec_template_spec_patterns := {"Deployment", "ReplicaSet", "DaemonSet", "StatefulSet", "Pod", "Job", "CronJob"}
92-
spec_template_spec_patterns[wl.kind]
93-
wl_connected_to_service(wl, svc)
94-
95-
result := svc_connected_to_httproute(svc, httproute)
96-
97-
msga := {
98-
"alertMessage": sprintf("workload '%v' is exposed through httproute '%v'", [wl.metadata.name, httproute.metadata.name]),
99-
"packagename": "armo_builtins",
100-
"failedPaths": [],
101-
"fixPaths": [],
102-
"alertScore": 7,
103-
"alertObject": {
104-
"k8sApiObjects": [wl]
105-
},
106-
"relatedObjects": [
107-
{
108-
"object": httproute,
109-
"reviewPaths": result,
110-
"failedPaths": result,
111-
},
112-
{
113-
"object": svc,
114-
}
115-
]
116-
}
117-
}
118-
11975
# ====================================================================================
12076

12177
is_exposed_service(svc) {
@@ -146,11 +102,4 @@ svc_connected_to_ingress(svc, ingress) = result {
146102
result := [sprintf("spec.rules[%d].http.paths[%d].backend.service.name", [i,j])]
147103
}
148104

149-
svc_connected_to_httproute(svc, httproute) = result {
150-
rule := httproute.spec.rules[i]
151-
ref := rule.backendRefs[j]
152-
ref.kind == "Service"
153-
svc.metadata.name == ref.name
154-
result := [sprintf("spec.rules[%d].backendRefs[%d].name", [i,j])]
155-
}
156105

rules/exposure-to-internet/rule.metadata.json

-11
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,6 @@
5252
"resources": [
5353
"Ingress"
5454
]
55-
},
56-
{
57-
"apiGroups": [
58-
"gateway.networking.k8s.io"
59-
],
60-
"apiVersions": [
61-
"v1"
62-
],
63-
"resources": [
64-
"HTTPRoute"
65-
]
6655
}
6756
],
6857
"description": "fails in case the running workload has binded Service or Ingress that are exposing it on Internet.",

0 commit comments

Comments
 (0)