Skip to content

Commit 0b49428

Browse files
committed
Support HTTPRoute in Gateway API
Signed-off-by: Ben <[email protected]>
1 parent 9534324 commit 0b49428

File tree

7 files changed

+271
-4
lines changed

7 files changed

+271
-4
lines changed

rules/exposure-to-internet/raw.rego

+60-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ deny[msga] {
55
service := input[_]
66
service.kind == "Service"
77
is_exposed_service(service)
8-
8+
99
wl := input[_]
1010
spec_template_spec_patterns := {"Deployment", "ReplicaSet", "DaemonSet", "StatefulSet", "Pod", "Job", "CronJob"}
1111
spec_template_spec_patterns[wl.kind]
@@ -32,7 +32,7 @@ deny[msga] {
3232
deny[msga] {
3333
ingress := input[_]
3434
ingress.kind == "Ingress"
35-
35+
3636
svc := input[_]
3737
svc.kind == "Service"
3838

@@ -49,7 +49,7 @@ deny[msga] {
4949
wl_connected_to_service(wl, svc)
5050

5151
result := svc_connected_to_ingress(svc, ingress)
52-
52+
5353
msga := {
5454
"alertMessage": sprintf("workload '%v' is exposed through ingress '%v'", [wl.metadata.name, ingress.metadata.name]),
5555
"packagename": "armo_builtins",
@@ -70,7 +70,51 @@ deny[msga] {
7070
}
7171
]
7272
}
73-
}
73+
}
74+
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+
}
74118

75119
# ====================================================================================
76120

@@ -90,6 +134,10 @@ wl_connected_to_service(wl, svc) {
90134
wl.spec.selector.matchLabels == svc.spec.selector
91135
}
92136

137+
wl_connected_to_service(wl, svc) {
138+
count({x | svc.spec.selector[x] == wl.spec.template.metadata.labels[x]}) == count(svc.spec.selector)
139+
}
140+
93141
# check if service is connected to ingress
94142
svc_connected_to_ingress(svc, ingress) = result {
95143
rule := ingress.spec.rules[i]
@@ -98,3 +146,11 @@ svc_connected_to_ingress(svc, ingress) = result {
98146
result := [sprintf("spec.rules[%d].http.paths[%d].backend.service.name", [i,j])]
99147
}
100148

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+
}
156+

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

+11
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@
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+
]
5566
}
5667
],
5768
"description": "fails in case the running workload has binded Service or Ingress that are exposing it on Internet.",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[
2+
{
3+
"alertMessage": "workload 'httpbin' is exposed through httproute 'httpbin'",
4+
"failedPaths": [],
5+
"fixPaths": [],
6+
"ruleStatus": "",
7+
"packagename": "armo_builtins",
8+
"alertScore": 7,
9+
"alertObject": {
10+
"k8sApiObjects": [
11+
{
12+
"apiVersion": "apps/v1",
13+
"kind": "Deployment",
14+
"metadata": {
15+
"name": "httpbin"
16+
}
17+
}
18+
]
19+
}
20+
}
21+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
annotations:
5+
deployment.kubernetes.io/revision: "1"
6+
creationTimestamp: "2024-02-04T19:05:12Z"
7+
generation: 1
8+
name: httpbin
9+
namespace: httpbin
10+
resourceVersion: "870"
11+
uid: 7462bb4c-b5a2-413e-80ee-c1baaf34aade
12+
spec:
13+
progressDeadlineSeconds: 600
14+
replicas: 1
15+
revisionHistoryLimit: 10
16+
selector:
17+
matchLabels:
18+
app: httpbin
19+
version: v1
20+
strategy:
21+
rollingUpdate:
22+
maxSurge: 25%
23+
maxUnavailable: 25%
24+
type: RollingUpdate
25+
template:
26+
metadata:
27+
labels:
28+
app: httpbin
29+
version: v1
30+
spec:
31+
containers:
32+
- args:
33+
- -port
34+
- "8080"
35+
- -max-duration
36+
- 600s
37+
command:
38+
- go-httpbin
39+
image: docker.io/mccutchen/go-httpbin:v2.6.0
40+
imagePullPolicy: IfNotPresent
41+
name: httpbin
42+
ports:
43+
- containerPort: 8080
44+
protocol: TCP
45+
resources: {}
46+
terminationMessagePath: /dev/termination-log
47+
terminationMessagePolicy: File
48+
- command:
49+
- tail
50+
- -f
51+
- /dev/null
52+
image: curlimages/curl:7.83.1
53+
imagePullPolicy: IfNotPresent
54+
name: curl
55+
resources:
56+
limits:
57+
cpu: 200m
58+
requests:
59+
cpu: 100m
60+
terminationMessagePath: /dev/termination-log
61+
terminationMessagePolicy: File
62+
- image: gcr.io/solo-public/docs/hey:0.1.4
63+
imagePullPolicy: IfNotPresent
64+
name: hey
65+
resources: {}
66+
terminationMessagePath: /dev/termination-log
67+
terminationMessagePolicy: File
68+
dnsPolicy: ClusterFirst
69+
restartPolicy: Always
70+
schedulerName: default-scheduler
71+
securityContext: {}
72+
serviceAccount: httpbin
73+
serviceAccountName: httpbin
74+
terminationGracePeriodSeconds: 30
75+
status:
76+
availableReplicas: 1
77+
conditions:
78+
- lastTransitionTime: "2024-02-04T19:05:32Z"
79+
lastUpdateTime: "2024-02-04T19:05:32Z"
80+
message: Deployment has minimum availability.
81+
reason: MinimumReplicasAvailable
82+
status: "True"
83+
type: Available
84+
- lastTransitionTime: "2024-02-04T19:05:12Z"
85+
lastUpdateTime: "2024-02-04T19:05:32Z"
86+
message: ReplicaSet "httpbin-f46cc8b9b" has successfully progressed.
87+
reason: NewReplicaSetAvailable
88+
status: "True"
89+
type: Progressing
90+
observedGeneration: 1
91+
readyReplicas: 1
92+
replicas: 1
93+
updatedReplicas: 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
kind: HTTPRoute
3+
metadata:
4+
creationTimestamp: "2024-02-04T19:06:03Z"
5+
generation: 1
6+
labels:
7+
example: httpbin-route
8+
name: httpbin
9+
namespace: httpbin
10+
resourceVersion: "914"
11+
uid: fd820080-801d-4fa7-934a-e23abe8bf746
12+
spec:
13+
hostnames:
14+
- www.example.com
15+
parentRefs:
16+
- group: gateway.networking.k8s.io
17+
kind: Gateway
18+
name: http
19+
namespace: gloo-system
20+
rules:
21+
- backendRefs:
22+
- group: ""
23+
kind: Service
24+
name: httpbin
25+
port: 8000
26+
weight: 1
27+
matches:
28+
- path:
29+
type: PathPrefix
30+
value: /
31+
status:
32+
parents:
33+
- conditions:
34+
- lastTransitionTime: "2024-02-04T19:06:03Z"
35+
message: ""
36+
observedGeneration: 1
37+
reason: Accepted
38+
status: "True"
39+
type: Accepted
40+
- lastTransitionTime: "2024-02-04T19:06:03Z"
41+
message: ""
42+
observedGeneration: 1
43+
reason: ResolvedRefs
44+
status: "True"
45+
type: ResolvedRefs
46+
controllerName: solo.io/gloo-gateway
47+
parentRef:
48+
group: gateway.networking.k8s.io
49+
kind: Gateway
50+
name: http
51+
namespace: gloo-system
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
creationTimestamp: "2024-02-04T19:05:12Z"
5+
labels:
6+
app: httpbin
7+
service: httpbin
8+
name: httpbin
9+
namespace: httpbin
10+
resourceVersion: "811"
11+
uid: c391feb7-54e5-41b2-869b-33166869f1b7
12+
spec:
13+
clusterIP: 10.96.162.234
14+
clusterIPs:
15+
- 10.96.162.234
16+
internalTrafficPolicy: Cluster
17+
ipFamilies:
18+
- IPv4
19+
ipFamilyPolicy: SingleStack
20+
ports:
21+
- name: http
22+
port: 8000
23+
protocol: TCP
24+
targetPort: 8080
25+
- name: tcp
26+
port: 9000
27+
protocol: TCP
28+
targetPort: 9000
29+
selector:
30+
app: httpbin
31+
sessionAffinity: None
32+
type: ClusterIP
33+
status:
34+
loadBalancer: {}

testrunner/opaprocessor/processorutils.go

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ func AssertResponses(t *testing.T, responses []reporthandling.RuleResponse, expe
161161
return err
162162
}
163163

164+
//fmt.Println("actual:", string(actual))
164165
require.JSONEq(t, string(expected), string(actual))
165166
return nil
166167
}

0 commit comments

Comments
 (0)