-
Notifications
You must be signed in to change notification settings - Fork 109
WIP: E2E test case for Kmesh L4 authorization #641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
722aff8
a668f69
43a7fde
d927b90
f45941c
820b570
fc95d15
2cab055
c10f1f2
a2e5ba7
b4775df
335cb2a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,9 +106,11 @@ SEC("xdp_auth") | |
int xdp_authz(struct xdp_md *ctx) | ||
{ | ||
if (!is_authz_offload_enabled()) { | ||
BPF_LOG(INFO, XDP, "offload authorization is DISABLED"); | ||
bpf_tail_call(ctx, &map_of_xdp_tailcall, TAIL_CALL_AUTH_IN_USER_SPACE); | ||
return XDP_PASS; | ||
} | ||
BPF_LOG(INFO, XDP, "offload authorization is ENABLED"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||
|
||
struct match_context match_ctx = {0}; | ||
struct bpf_sock_tuple tuple_key = {0}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ import ( | |
"fmt" | ||
"net/http" | ||
"net/netip" | ||
"os/exec" | ||
"sort" | ||
"strings" | ||
"testing" | ||
|
@@ -689,6 +690,141 @@ func TestBookinfo(t *testing.T) { | |
}) | ||
} | ||
|
||
func TestAuthorizationL4(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we can split test cases by the functionalities |
||
framework.NewTest(t).Run(func(t framework.TestContext) { | ||
t.NewSubTest("L4 Authorization").Run(func(t framework.TestContext) { | ||
// Enable authorizaiton offload to xdp. | ||
|
||
if len(apps.ServiceWithWaypointAtServiceGranularity) == 0 { | ||
t.Fatal(fmt.Errorf("need at least 1 instance of apps.ServiceWithWaypointAtServiceGranularity")) | ||
} | ||
src := apps.ServiceWithWaypointAtServiceGranularity[0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do you choose this special workload as a src client There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no specific choice, any workload managed by Kmesh is OK. |
||
|
||
clients := src.WorkloadsOrFail(t) | ||
dst := apps.EnrolledToKmesh | ||
|
||
addresses := clients.Addresses() | ||
if len(addresses) < 2 { | ||
t.Fatal(fmt.Errorf("need at least 2 clients")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? why require at least 2 addresses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One for |
||
} | ||
selectedAddress := addresses[0] | ||
|
||
authzCases := []struct { | ||
name string | ||
spec string | ||
}{ | ||
{ | ||
name: "allow", | ||
spec: ` | ||
action: ALLOW | ||
`, | ||
}, | ||
{ | ||
name: "deny", | ||
spec: ` | ||
action: DENY | ||
`, | ||
}, | ||
} | ||
|
||
chooseChecker := func(action string, ip string) echo.Checker { | ||
switch action { | ||
case "allow": | ||
if ip != selectedAddress { | ||
return check.NotOK() | ||
} else { | ||
return check.OK() | ||
} | ||
case "deny": | ||
if ip != selectedAddress { | ||
return check.OK() | ||
} else { | ||
return check.NotOK() | ||
} | ||
default: | ||
t.Fatal("invalid action") | ||
} | ||
|
||
return check.OK() | ||
} | ||
|
||
count := 0 | ||
workloads := dst.WorkloadsOrFail(t) | ||
for _, client := range workloads { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, this is the server instance |
||
if count == len(workloads) { | ||
break | ||
} | ||
podName := client.PodName() | ||
namespace := apps.Namespace.Name() | ||
timeout := time.After(5 * time.Second) | ||
ticker := time.NewTicker(500 * time.Millisecond) | ||
defer ticker.Stop() | ||
InnerLoop: | ||
for { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is retry.Until that can be used |
||
select { | ||
case <-timeout: | ||
t.Fatalf("Timeout: XDP eBPF program not found on pod %s", podName) | ||
case <-ticker.C: | ||
cmd := exec.Command("kubectl", "exec", "-n", namespace, podName, "--", "sh", "-c", "ip a | grep xdp") | ||
output, err := cmd.CombinedOutput() | ||
if err == nil && len(output) > 0 { | ||
t.Logf("XDP program is loaded on pod %s", podName) | ||
count++ | ||
break InnerLoop | ||
} | ||
t.Logf("Waiting for XDP program to load on pod %s: %v", podName, err) | ||
} | ||
} | ||
} | ||
|
||
for _, tc := range authzCases { | ||
t.ConfigIstio().Eval(apps.Namespace.Name(), map[string]string{ | ||
"Destination": dst.Config().Service, | ||
"Ip": selectedAddress, | ||
}, `apiVersion: security.istio.io/v1beta1 | ||
kind: AuthorizationPolicy | ||
metadata: | ||
name: policy | ||
spec: | ||
selector: | ||
matchLabels: | ||
app: "{{.Destination}}" | ||
`+tc.spec+` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A hacky way, would prefer using fmt.Sprintf or golang template |
||
rules: | ||
- from: | ||
- source: | ||
ipBlocks: | ||
- "{{.Ip}}" | ||
`).ApplyOrFail(t) | ||
|
||
for _, client := range clients { | ||
opt := echo.CallOptions{ | ||
To: dst, | ||
Port: echo.Port{Name: "tcp"}, | ||
Scheme: scheme.TCP, | ||
NewConnectionPerRequest: true, | ||
// Due to the mechanism of Kmesh L4 authorization, we need to set the timeout slightly longer. | ||
Timeout: time.Minute * 2, | ||
} | ||
|
||
var name string | ||
if client.Address() != selectedAddress { | ||
name = tc.name + ", not selected address" | ||
} else { | ||
name = tc.name + ", selected address" | ||
} | ||
|
||
opt.Check = chooseChecker(tc.name, client.Address()) | ||
|
||
t.NewSubTestf("%v", name).Run(func(t framework.TestContext) { | ||
src.WithWorkloads(client).CallOrFail(t, opt) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shoudn't you wait until the policy has been populated? I cannot understand how you make it |
||
}) | ||
} | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
func runTest(t *testing.T, f func(t framework.TestContext, src echo.Instance, dst echo.Instance, opt echo.CallOptions)) { | ||
framework.NewTest(t).Run(func(t framework.TestContext) { | ||
runTestContext(t, f) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove