Skip to content

Commit

Permalink
Add a l7 header replace test
Browse files Browse the repository at this point in the history
This adds a test for the L7 policy to add/replace a HTTP header in a
request. It does this by sending a request to a new endpoint that
required an auth header, which will succeed if injected from a secret

Signed-off-by: Maartje Eyskens <[email protected]>
  • Loading branch information
meyskens committed Mar 20, 2023
1 parent 21916db commit f6618a2
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 8 deletions.
9 changes: 9 additions & 0 deletions connectivity/check/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,15 @@ var (
ExitCode: ExitCurlHTTPError,
}

// ResultDNSOKCurlHTTPError expects a failed command, generating DNS traffic and without a dropped flow.
ResultDNSOKCurlHTTPError = Result{
DNSProxy: true,
L7Proxy: true,
Drop: false,
DropReasonFunc: defaultDropReason,
ExitCode: ExitCurlHTTPError,
}

// ResultDrop expects a dropped flow and a failed command.
ResultDrop = Result{
Drop: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
# client2 is allowed to contact the echo Pod
# on port 8080 via POST method. HTTP introspection is enabled for client2.
# The request to /auth-header-required will be injected with an auth header to work
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: client-egress-l7-http-matchheader-secret
spec:
description: "Allow POST <echo>:8080/auth-header-required and set the header from client2"
endpointSelector:
matchLabels:
other: client
egress:
# Allow POST /auth-header-required requests towards echo pods with added header.
- toEndpoints:
- matchLabels:
kind: echo
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "POST"
path: "/auth-header-required$"
headerMatches:
- name: Authorization
mismatch: REPLACE
secret:
namespace: "{{.TestNamespace}}"
name: header-match
43 changes: 37 additions & 6 deletions connectivity/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"fmt"

"github.com/blang/semver/v4"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/cilium/cilium-cli/connectivity/check"
"github.com/cilium/cilium-cli/connectivity/tests"
Expand Down Expand Up @@ -98,6 +100,9 @@ var (
//go:embed manifests/client-egress-l7-tls.yaml
clientEgressL7TLSPolicyYAML string

//go:embed manifests/client-egress-l7-http-matchheader-secret.yaml
clientEgressL7HTTPMatchheaderSecretYAML string

//go:embed manifests/echo-ingress-l7-http.yaml
echoIngressL7HTTPPolicyYAML string

Expand Down Expand Up @@ -125,12 +130,13 @@ func Run(ctx context.Context, ct *check.ConnectivityTest) error {

// render templates, if any problems fail early
for key, temp := range map[string]string{
"clientEgressToCIDR1111PolicyYAML": clientEgressToCIDR1111PolicyYAML,
"clientEgressToCIDR1111DenyPolicyYAML": clientEgressToCIDR1111DenyPolicyYAML,
"clientEgressL7HTTPPolicyYAML": clientEgressL7HTTPPolicyYAML,
"clientEgressL7HTTPNamedPortPolicyYAML": clientEgressL7HTTPNamedPortPolicyYAML,
"clientEgressToFQDNsCiliumIOPolicyYAML": clientEgressToFQDNsCiliumIOPolicyYAML,
"clientEgressL7TLSPolicyYAML": clientEgressL7TLSPolicyYAML,
"clientEgressToCIDR1111PolicyYAML": clientEgressToCIDR1111PolicyYAML,
"clientEgressToCIDR1111DenyPolicyYAML": clientEgressToCIDR1111DenyPolicyYAML,
"clientEgressL7HTTPPolicyYAML": clientEgressL7HTTPPolicyYAML,
"clientEgressL7HTTPNamedPortPolicyYAML": clientEgressL7HTTPNamedPortPolicyYAML,
"clientEgressToFQDNsCiliumIOPolicyYAML": clientEgressToFQDNsCiliumIOPolicyYAML,
"clientEgressL7TLSPolicyYAML": clientEgressL7TLSPolicyYAML,
"clientEgressL7HTTPMatchheaderSecretYAML": clientEgressL7HTTPMatchheaderSecretYAML,
} {
val, err := utils.RenderTemplate(temp, ct.Params())
if err != nil {
Expand Down Expand Up @@ -697,6 +703,31 @@ func Run(ctx context.Context, ct *check.ConnectivityTest) error {
return check.ResultOK, check.ResultNone
})

// Test L7 HTTP with a header replace set in the policy
ct.NewTest("client-egress-l7-set-header").
WithFeatureRequirements(check.RequireFeatureEnabled(check.FeatureL7Proxy)).
WithFeatureRequirements(check.RequireFeatureEnabled(check.FeatureSecretBackendK8s)).
WithSecret(&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "header-match",
},
Data: map[string][]byte{
"value": []byte("Bearer 123456"),
},
}).
WithPolicy(renderedTemplates["clientEgressL7HTTPMatchheaderSecretYAML"]). // L7 allow policy with HTTP introspection (POST only)
WithScenarios(
tests.PodToPodWithEndpoints(tests.WithMethod("POST"), tests.WithPath("auth-header-required"), tests.WithDestinationLabelsOption(map[string]string{"other": "echo"})),
tests.PodToPodWithEndpoints(tests.WithMethod("POST"), tests.WithPath("auth-header-required"), tests.WithDestinationLabelsOption(map[string]string{"first": "echo"})),
).
WithExpectations(func(a *check.Action) (egress, ingress check.Result) {
if a.Source().HasLabel("other", "client") && // Only client2 has the header policy.
(a.Destination().Port() == 8080) { // port 8080 is traffic to echo Pod.
return check.ResultOK, check.ResultNone
}
return check.ResultDNSOKCurlHTTPError, check.ResultNone // if the header is not set the request will get a 403
})

// Only allow UDP:53 to kube-dns, no DNS proxy enabled.
ct.NewTest("dns-only").WithPolicy(clientEgressOnlyDNSPolicyYAML).
WithFeatureRequirements(check.RequireFeatureEnabled(check.FeatureL7Proxy)).
Expand Down
7 changes: 7 additions & 0 deletions connectivity/tests/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type labelsOption struct {
sourceLabels map[string]string
destinationLabels map[string]string
method string
path string
}

func WithMethod(method string) Option {
Expand All @@ -33,6 +34,12 @@ func WithDestinationLabelsOption(destinationLabels map[string]string) Option {
}
}

func WithPath(path string) Option {
return func(option *labelsOption) {
option.path = path
}
}

func hasAllLabels(labelsContainer labelsContainer, filters map[string]string) bool {
for k, v := range filters {
if !labelsContainer.HasLabel(k, v) {
Expand Down
9 changes: 8 additions & 1 deletion connectivity/tests/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func PodToPodWithEndpoints(opts ...Option) check.Scenario {
sourceLabels: options.sourceLabels,
destinationLabels: options.destinationLabels,
method: options.method,
path: options.path,
}
}

Expand All @@ -84,6 +85,7 @@ type podToPodWithEndpoints struct {
sourceLabels map[string]string
destinationLabels map[string]string
method string
path string
}

func (s *podToPodWithEndpoints) Name() string {
Expand Down Expand Up @@ -123,7 +125,12 @@ func (s *podToPodWithEndpoints) curlEndpoints(ctx context.Context, t *check.Test
}

// Manually construct an HTTP endpoint for each API endpoint.
for _, path := range []string{"public", "private"} {
paths := []string{"public", "private"}
if s.path != "" { // Override default paths if one is set
paths = []string{s.path}
}

for _, path := range paths {
epName := fmt.Sprintf("%s-%s", name, path)
url := fmt.Sprintf("%s/%s", baseURL, path)
ep := check.HTTPEndpointWithLabels(epName, url, echo.Labels())
Expand Down
2 changes: 1 addition & 1 deletion defaults/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const (

ConnectivityCheckAlpineCurlImage = "quay.io/cilium/alpine-curl:v1.6.0@sha256:408430f548a8390089b9b83020148b0ef80b0be1beb41a98a8bfe036709c196e"
ConnectivityPerformanceImage = "quay.io/cilium/network-perf:a816f935930cb2b40ba43230643da4d5751a5711@sha256:679d3a370c696f63884da4557a4466f3b5569b4719bb4f86e8aac02fbe390eea"
ConnectivityCheckJSONMockImage = "quay.io/cilium/json-mock:v1.3.3@sha256:f26044a2b8085fcaa8146b6b8bb73556134d7ec3d5782c6a04a058c945924ca0"
ConnectivityCheckJSONMockImage = "quay.io/cilium/json-mock-ci:latest@sha256:5be90d8c2adc99f13bc42d7198d81fe179a2925b8091fc73437b9ba3b290afec" // MAARTJE FIX THIS
ConnectivityDNSTestServerImage = "docker.io/coredns/coredns:1.10.0@sha256:017727efcfeb7d053af68e51436ce8e65edbc6ca573720afb4f79c8594036955"

ConfigMapName = "cilium-config"
Expand Down

0 comments on commit f6618a2

Please sign in to comment.