Skip to content

Commit e62b37b

Browse files
authored
Merge pull request #8575 from zalando-incubator/opa-e2e-tests
Add ingress test for opaAuthorizeRequest filter
2 parents ce5b068 + 44fa49b commit e62b37b

File tree

6 files changed

+185
-1
lines changed

6 files changed

+185
-1
lines changed

delivery.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pipeline:
8080
value: "teapot-kubernetes-e2e-results"
8181
- name: ETCD_ENDPOINTS
8282
value: "https://etcd-server.etcd.teapot-e2e.zalan.do:2479"
83+
- name: SKIPPER_OPA_ENABLED
84+
value: "true"
8385
- name: HOSTED_ZONE
8486
valueFrom:
8587
configMapKeyRef:
@@ -155,6 +157,26 @@ pipeline:
155157
secretKeyRef:
156158
name: kubernetes-e2e-config-secret
157159
key: "OKTA_AUTH_ISSUER_URL"
160+
- name: STYRA_TOKEN
161+
valueFrom:
162+
secretKeyRef:
163+
name: kubernetes-e2e-config-secret
164+
key: "STYRA_TOKEN"
165+
- name: SKIPPER_OPA_BUCKET_ARN
166+
valueFrom:
167+
secretKeyRef:
168+
name: kubernetes-e2e-config-secret
169+
key: "SKIPPER_OPA_BUCKET_ARN"
170+
- name: SKIPPER_OPA_OBSERVABILITY_URL
171+
valueFrom:
172+
secretKeyRef:
173+
name: kubernetes-e2e-config-secret
174+
key: "SKIPPER_OPA_OBSERVABILITY_URL"
175+
- name: SKIPPER_OPA_BUNDLES_URL
176+
valueFrom:
177+
secretKeyRef:
178+
name: kubernetes-e2e-config-secret
179+
key: "SKIPPER_OPA_BUNDLES_URL"
158180
- name: CLUSTER_ADMIN_TOKEN
159181
valueFrom:
160182
secretKeyRef:

test/e2e/aaas.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
. "github.com/onsi/ginkgo/v2"
8+
. "github.com/onsi/gomega"
9+
10+
netv1 "k8s.io/api/networking/v1"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/client-go/kubernetes"
13+
"k8s.io/kubernetes/test/e2e/framework"
14+
"k8s.io/kubernetes/test/e2e/framework/ingress"
15+
admissionapi "k8s.io/pod-security-admission/api"
16+
"net/http"
17+
"time"
18+
)
19+
20+
var _ = Describe("Ingress tests for OPA filters", func() {
21+
f := framework.NewDefaultFramework("skipper-ingress-with-opa")
22+
f.NamespacePodSecurityEnforceLevel = admissionapi.LevelBaseline
23+
24+
var (
25+
cs kubernetes.Interface
26+
jig *ingress.TestJig
27+
ingressCreate *netv1.Ingress
28+
ns string
29+
hostName string
30+
port int
31+
serviceName = "aaas-infrastructure-tests"
32+
opaPolicyName = "aaas-infrastructure-tests"
33+
)
34+
35+
BeforeEach(func() {
36+
jig = ingress.NewIngressTestJig(f.ClientSet)
37+
cs = f.ClientSet
38+
ns = f.Namespace.Name
39+
hostName = fmt.Sprintf("%s-%d.%s", serviceName, time.Now().UTC().Unix(), E2EHostedZone())
40+
port = 8080
41+
42+
ingressCreate = createIngressWithInfo(serviceName, hostName, ns, port, cs, jig)
43+
})
44+
45+
It("opaAuthorizeRequest filter should pass through authorized requests [Ingress] [Opa]", func() {
46+
// Authorization done with the rule
47+
// https://github.bus.zalan.do/corporate-iam/aaas-infrastructure-tests-policies/blob/main/bundle/policy/ingress/rules.rego
48+
49+
authorizationEnforcedPath := "/auth"
50+
path := "/"
51+
ingressRoute := fmt.Sprintf(`authorize: PathRegexp("%s") -> modPath("%s", "%s") -> opaAuthorizeRequest("%s") -> inlineContent("Got response") -> <shunt>;`, authorizationEnforcedPath, authorizationEnforcedPath, path, opaPolicyName)
52+
ingressUpdate := updateIngressAndWait(serviceName, hostName, path, ingressRoute, port, ingressCreate, cs)
53+
54+
By(fmt.Sprintf("Calling ingress %s/%s we wait to get a 403 with opaAuthorizeRequest %s policy", ingressUpdate.Namespace, ingressUpdate.Name, opaPolicyName))
55+
rt, quit := createHTTPRoundTripper()
56+
defer func() {
57+
quit <- struct{}{}
58+
}()
59+
60+
url := "https://" + hostName + authorizationEnforcedPath
61+
req, err := http.NewRequest("GET", url, nil)
62+
resp, err := getAndWaitResponse(rt, req, 10*time.Second, http.StatusForbidden)
63+
framework.ExpectNoError(err)
64+
Expect(resp.StatusCode).To(Equal(http.StatusForbidden))
65+
66+
By(fmt.Sprintf("Calling ingress %s/%s we wait to get a 200 with opaAuthorizeRequest %s policy", ingressUpdate.Namespace, ingressUpdate.Name, opaPolicyName))
67+
req.Header.Set("Authorization", "Basic valid_token") // Authorized request
68+
resp, err = getAndWaitResponse(rt, req, 10*time.Second, http.StatusOK)
69+
framework.ExpectNoError(err)
70+
Expect(resp.StatusCode).To(Equal(http.StatusOK))
71+
s, err := getBody(resp)
72+
framework.ExpectNoError(err)
73+
Expect(s).To(Equal("Got response"))
74+
})
75+
76+
It("opaServeResponse filter should return body [Ingress] [Opa]", func() {
77+
// Authorization done with the rule
78+
// https://github.bus.zalan.do/corporate-iam/aaas-infrastructure-tests-policies/blob/main/bundle/policy/ingress/permissions.rego
79+
80+
serveResponsePath := "/permissions"
81+
expectedPermissionsContent := "\"permissions\":{\"permission1\":{},\"permission2\":{}}"
82+
path := serveResponsePath
83+
ingressRoute := fmt.Sprintf(`authorize: PathRegexp("%s") -> opaServeResponse("%s") -> <shunt>;`, serveResponsePath, opaPolicyName)
84+
ingressUpdate := updateIngressAndWait(serviceName, hostName, path, ingressRoute, port, ingressCreate, cs)
85+
86+
By(fmt.Sprintf("Calling ingress %s/%s we wait to get a 403 with opaServeResponse %s policy", ingressUpdate.Namespace, ingressUpdate.Name, opaPolicyName))
87+
rt, quit := createHTTPRoundTripper()
88+
defer func() {
89+
quit <- struct{}{}
90+
}()
91+
92+
url := "https://" + hostName + serveResponsePath
93+
req, err := http.NewRequest("GET", url, nil)
94+
resp, err := getAndWaitResponse(rt, req, 10*time.Second, http.StatusForbidden)
95+
framework.ExpectNoError(err)
96+
Expect(resp.StatusCode).To(Equal(http.StatusForbidden))
97+
98+
By(fmt.Sprintf("Calling ingress %s/%s we wait to get a 200 with opaServeResponse %s policy", ingressUpdate.Namespace, ingressUpdate.Name, opaPolicyName))
99+
req.Header.Set("Authorization", "Basic permissions_token") // Authorized request
100+
resp, err = getAndWaitResponse(rt, req, 10*time.Second, http.StatusOK)
101+
framework.ExpectNoError(err)
102+
Expect(resp.StatusCode).To(Equal(http.StatusOK))
103+
s, err := getBody(resp)
104+
framework.ExpectNoError(err)
105+
Expect(s).To(ContainSubstring(expectedPermissionsContent))
106+
})
107+
108+
})
109+
110+
func createIngressWithInfo(serviceName, hostName, ns string, port int, cs kubernetes.Interface, jig *ingress.TestJig) *netv1.Ingress {
111+
labels := map[string]string{"app": serviceName}
112+
waitTime := 10 * time.Minute
113+
114+
// Create initial ingress
115+
ing := createIngress(serviceName, hostName, ns, "/", netv1.PathTypeImplementationSpecific, labels, nil, port)
116+
var err error
117+
ingressCreate, err := cs.NetworkingV1().Ingresses(ns).Create(context.TODO(), ing, metav1.CreateOptions{})
118+
framework.ExpectNoError(err)
119+
120+
// Wait for ingress address
121+
addr, err := jig.WaitForIngressAddress(context.TODO(), cs, ns, ingressCreate.Name, waitTime)
122+
framework.ExpectNoError(err)
123+
124+
// Ensure ingress exists
125+
_, err = cs.NetworkingV1().Ingresses(ns).Get(context.TODO(), ing.Name, metav1.GetOptions{ResourceVersion: "0"})
126+
framework.ExpectNoError(err)
127+
128+
By("Waiting for LB to create endpoint and skipper route")
129+
err = waitForResponse(addr, "https", waitTime, isNotFound, true)
130+
framework.ExpectNoError(err)
131+
132+
return ingressCreate
133+
}
134+
135+
func updateIngressAndWait(serviceName, hostName, path, ingressRoute string, port int, ingressCreate *netv1.Ingress, cs kubernetes.Interface) *netv1.Ingress {
136+
updatedIng := updateIngress(ingressCreate.ObjectMeta.Name,
137+
ingressCreate.ObjectMeta.Namespace,
138+
hostName,
139+
serviceName,
140+
path,
141+
netv1.PathTypeImplementationSpecific,
142+
ingressCreate.ObjectMeta.Labels,
143+
map[string]string{
144+
"zalando.org/skipper-routes": ingressRoute,
145+
},
146+
port,
147+
)
148+
ingressUpdate, err := cs.NetworkingV1().Ingresses(ingressCreate.ObjectMeta.Namespace).Update(context.TODO(), updatedIng, metav1.UpdateOptions{})
149+
framework.ExpectNoError(err)
150+
time.Sleep(2 * time.Minute) // wait for routing change propagation
151+
152+
return ingressUpdate
153+
}

test/e2e/apply/secret.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ data:
1919
ETCD_SCALYR_KEY: "deployment-secret:2:stups-test:AQICAHjXIrc66g/+P4X1Gl4MKcInWmwpFxivAqFGMI0fr9DvCwETRzvm1hGplyUn23FEXUVtAAAAnjCBmwYJKoZIhvcNAQcGoIGNMIGKAgEAMIGEBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDOfPJJJy60sDkZEIHgIBEIBXiANNciEqpcuZ3hFPCt6NkFtk0WBTSasDQHHbyuR8O+n5iM9k8/nUTLUrFlhba8blArq/ALE8vuKNdlS17q6PxGlvwJFFXQn/McohMpdyfnfQYKW8MPCu"
2020
OKTA_AUTH_ISSUER_URL: "deployment-secret:2:stups-test:AQICAHjXIrc66g/+P4X1Gl4MKcInWmwpFxivAqFGMI0fr9DvCwGmCMhSN2Er1sw2ofYnI44EAAAApDCBoQYJKoZIhvcNAQcGoIGTMIGQAgEAMIGKBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO2IC+r/zcUzXoQEHAIBEIBdrFchwu9i7LpMbyDbslu/lBxvfyh+nCGK33jtcxT3RdxuTXWuSJhkX+gU4cgFXAI5LLnXh4M20jHUEEPU78MJWR47HLTPGPJcKQj5fOpPqpD3duuKIrZDRm5ba6AN"
2121
SESSION_MANAGER_DESTINATION_ARN: "deployment-secret:2:stups-test:AQICAHjXIrc66g/+P4X1Gl4MKcInWmwpFxivAqFGMI0fr9DvCwF7fOZ9i6BDvWdNEddR7LZOAAAArjCBqwYJKoZIhvcNAQcGoIGdMIGaAgEAMIGUBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDBJwU/Zns+mzOBgczQIBEIBn/86xpnVO2Apr5nG3waPEAGCFYDWdOXcaS7pFKdNIhpXaADtODQtEd874HcE0W2I3bjKr3d3ghJFdN8r0BZiSmTbgc0fn+5ZiBTyGBfzWP4BCzxjRMvURl/7MX8ygwL78hpSxyRypAQ=="
22+
STYRA_TOKEN: "deployment-secret:2:stups-test:AQICAHjXIrc66g/+P4X1Gl4MKcInWmwpFxivAqFGMI0fr9DvCwGba1bnMYs8qNGHMd7a66H8AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDE/go6xBMbsPDNgTsQIBEIB7E+VUre5YvyOJ8Apbi1SXMqNsr1rMp38is8iM5nP3LXHknTKIBZMgTeRilreIGQ25+UjWjBrTRUWmmD5jq6oN/d8t+0AEcLOpGZUplZSV+za31/3pAOPCFSqhUgzlUiI6LWW1kNKtmWwNh9aDEu4geiOAJSxJTAot6H77"
23+
SKIPPER_OPA_BUCKET_ARN: "deployment-secret:2:stups-test:AQICAHjXIrc66g/+P4X1Gl4MKcInWmwpFxivAqFGMI0fr9DvCwGZdCVDLsCdProfzvZU7UAwAAAAlzCBlAYJKoZIhvcNAQcGoIGGMIGDAgEAMH4GCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMehOf7Uu444SWS6kbAgEQgFFPMaa0flwHLpxrkYjJMK4jXc0q4kX+KGrB5GFjKuUgOUPmQ+ME/aQduxwl2+xUilrKP50/NLXgMNHjeeHuZfoyiSgpGFBM4z8L0N6ggf2uE5U="
24+
SKIPPER_OPA_OBSERVABILITY_URL: "deployment-secret:2:stups-test:AQICAHjXIrc66g/+P4X1Gl4MKcInWmwpFxivAqFGMI0fr9DvCwHl773AuNEvIpzaM6ycpDNSAAAAqzCBqAYJKoZIhvcNAQcGoIGaMIGXAgEAMIGRBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDGld6jpQ38gOzVcn0gIBEIBkTHbv3adeEfRntVTUQyyQkIhUnc0QXKtmtJEdvBoRzWiJIBKQUQuM1VBV0re3HkO8HSY59nkwyHEncBMkHJoI9rC2LJuWU20oCjPw9lbweih+6Sxo+nqkDrQd+mHp+uA9Om3KqA=="
25+
SKIPPER_OPA_BUNDLES_URL: "deployment-secret:2:stups-test:AQICAHjXIrc66g/+P4X1Gl4MKcInWmwpFxivAqFGMI0fr9DvCwFnhaIRP4+3Y69xp1ycTI7qAAAAsTCBrgYJKoZIhvcNAQcGoIGgMIGdAgEAMIGXBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDF9gAl70l2g2kwfnJgIBEIBqP/DgIhIu5x5XNR1Ubqinz6r4ttQoHty8nXd6mxie2r6NxHskNOqkiSactUKhNIhboNlNsO4p4rKEkhglTeFZlEQvgEYNioWPw39xqICnUDPVr+Kp0Yrs/bzPLPV9wOlB917UiT7WJNybPg=="

test/e2e/cluster_config.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ clusters:
4747
karpenter_pools_enabled: "true"
4848
okta_auth_client_id: "kubernetes.cluster.teapot-e2e"
4949
teapot_admission_controller_validate_pod_images_soft_fail_namespaces: "^kube-system$"
50+
skipper_open_policy_agent_enabled: "${SKIPPER_OPA_ENABLED}"
51+
skipper_open_policy_agent_styra_token: "${STYRA_TOKEN}"
52+
skipper_open_policy_agent_bucket_arn: "${SKIPPER_OPA_BUCKET_ARN}"
53+
skipper_open_policy_agent_observability_url: "${SKIPPER_OPA_OBSERVABILITY_URL}"
54+
skipper_open_policy_agent_bundles_url: "${SKIPPER_OPA_BUNDLES_URL}"
5055
criticality_level: 1
5156
environment: e2e
5257
id: ${CLUSTER_ID}

test/e2e/run_e2e.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ if [ "$e2e" = true ]; then
183183

184184
mkdir -p junit_reports
185185
ginkgo -procs=25 -flake-attempts=2 \
186-
-focus="(\[Conformance\]|\[StatefulSetBasic\]|\[Feature:StatefulSet\]\s\[Slow\].*mysql|\[Zalando\])" \
186+
-focus="(\[Conformance\]|\[StatefulSetBasic\]|\[Feature:StatefulSet\]\s\[Slow\].*mysql|\[Zalando\]|\[Opa\])" \
187187
-skip="(\[Serial\]|validates.that.there.is.no.conflict.between.pods.with.same.hostPort.but.different.hostIP.and.protocol|Should.create.gradual.traffic.routes)" \
188188
"e2e.test" -- \
189189
-delete-namespace-on-failure=false \

0 commit comments

Comments
 (0)