Skip to content
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

Add CEL for BackendTLSPolicy targetRefs #3496

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apis/v1alpha3/backendtlspolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ type BackendTLSPolicySpec struct {
//
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:message="sectionName must be specified when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))"
snorwin marked this conversation as resolved.
Show resolved Hide resolved
// +kubebuilder:validation:XValidation:message="sectionName must be unique when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))"
TargetRefs []v1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRefs"`

// Validation contains backend TLS validation configuration.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

233 changes: 207 additions & 26 deletions pkg/test/cel/backendtlspolicy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,210 @@ import (
"testing"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gatewayv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gatewayv1a3 "sigs.k8s.io/gateway-api/apis/v1alpha3"
v1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)

func TestBackendTLSPolicyTargetRefs(t *testing.T) {
tests := []struct {
name string
wantErrors []string
targetRefs []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName
}{
{
name: "invalid because duplicate target refs without section name",
wantErrors: []string{"sectionName must be unique when targetRefs includes 2 or more references to the same target"},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
}, {
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
}},
},
{
name: "invalid because duplicate target refs with only one section name",
wantErrors: []string{"sectionName must be specified when targetRefs includes 2 or more references to the same target"},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
}, {
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}},
},
{
name: "invalid because duplicate target refs with duplicate section names",
wantErrors: []string{"sectionName must be unique when targetRefs includes 2 or more references to the same target"},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}, {
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}},
},
{
name: "valid single targetRef without sectionName",
wantErrors: []string{},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
}},
},
{
name: "valid single targetRef with sectionName",
wantErrors: []string{},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}},
},
{
name: "valid because duplicate target refs with different section names",
wantErrors: []string{},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}, {
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("bar")),
}},
},
{
name: "valid because duplicate target refs with different names",
wantErrors: []string{},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
snorwin marked this conversation as resolved.
Show resolved Hide resolved
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}, {
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example2",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}},
},
{
name: "valid because duplicate target refs with different kinds",
wantErrors: []string{},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}, {
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("NotService"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}},
},
{
name: "valid because duplicate target refs with different groups",
wantErrors: []string{},
targetRefs: []gatewayv1a2.LocalPolicyTargetReferenceWithSectionName{{
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group(corev1.GroupName),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}, {
LocalPolicyTargetReference: gatewayv1a2.LocalPolicyTargetReference{
Group: gatewayv1a2.Group("svc.other.io"),
Kind: gatewayv1a2.Kind("Service"),
Name: "example",
},
SectionName: ptrTo(gatewayv1a2.SectionName("foo")),
}},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
policy := &gatewayv1a3.BackendTLSPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("foo-%v", time.Now().UnixNano()),
Namespace: metav1.NamespaceDefault,
},
Spec: gatewayv1a3.BackendTLSPolicySpec{
TargetRefs: tc.targetRefs,
Validation: gatewayv1a3.BackendTLSPolicyValidation{
WellKnownCACertificates: ptrTo(gatewayv1a3.WellKnownCACertificatesType("System")),
Hostname: "foo.example.com",
},
},
}
validateBackendTLSPolicy(t, policy, tc.wantErrors)
})
}
}

func TestBackendTLSPolicyValidation(t *testing.T) {
tests := []struct {
name string
wantErrors []string
routeConfig gatewayv1a3.BackendTLSPolicyValidation
name string
wantErrors []string
policyValidation gatewayv1a3.BackendTLSPolicyValidation
}{
{
name: "valid BackendTLSPolicyValidation with WellKnownCACertificates",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
WellKnownCACertificates: ptrTo(gatewayv1a3.WellKnownCACertificatesType("System")),
Hostname: "foo.example.com",
},
wantErrors: []string{},
},
{
name: "valid BackendTLSPolicyValidation with CACertificateRefs",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -60,13 +241,13 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
wantErrors: []string{},
},
{
name: "invalid BackendTLSPolicyValidation with missing fields",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{},
wantErrors: []string{"spec.validation.hostname in body should be at least 1 chars long", "must specify either CACertificateRefs or WellKnownCACertificates"},
name: "invalid BackendTLSPolicyValidation with missing fields",
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{},
wantErrors: []string{"spec.validation.hostname in body should be at least 1 chars long", "must specify either CACertificateRefs or WellKnownCACertificates"},
},
{
name: "invalid BackendTLSPolicyValidation with both CACertificateRefs and WellKnownCACertificates",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -82,15 +263,15 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "invalid BackendTLSPolicyValidation with Unsupported value for WellKnownCACertificates",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
WellKnownCACertificates: ptrTo(gatewayv1a3.WellKnownCACertificatesType("bar")),
Hostname: "foo.example.com",
},
wantErrors: []string{"supported values: \"System\""},
},
{
name: "invalid BackendTLSPolicyValidation with empty Hostname field",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -104,7 +285,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "valid BackendTLSPolicyValidation with SubjectAltName type Hostname",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -124,7 +305,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "valid BackendTLSPolicyValidation with SubjectAltName type URI",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -144,7 +325,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "invalid BackendTLSPolicyValidation with SubjectAltName type Hostname and empty Hostname field",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -164,7 +345,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "invalid BackendTLSPolicyValidation with SubjectAltName type URI and non-empty Hostname field",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -184,7 +365,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "invalid BackendTLSPolicyValidation with SubjectAltName type URI and empty URI field",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -204,7 +385,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "invalid BackendTLSPolicyValidation with SubjectAltName type Hostname and non-empty URI field",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -224,7 +405,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "invalid BackendTLSPolicyValidation with SubjectAltName type Hostname and both Hostname and URI specified",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -245,7 +426,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
},
{
name: "invalid BackendTLSPolicyValidation incorrect URI SAN",
routeConfig: gatewayv1a3.BackendTLSPolicyValidation{
policyValidation: gatewayv1a3.BackendTLSPolicyValidation{
CACertificateRefs: []v1beta1.LocalObjectReference{
{
Group: "group",
Expand All @@ -267,7 +448,7 @@ func TestBackendTLSPolicyValidation(t *testing.T) {

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
route := &gatewayv1a3.BackendTLSPolicy{
policy := &gatewayv1a3.BackendTLSPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("foo-%v", time.Now().UnixNano()),
Namespace: metav1.NamespaceDefault,
Expand All @@ -284,22 +465,22 @@ func TestBackendTLSPolicyValidation(t *testing.T) {
ptrTo(gatewayv1a2.SectionName("section")),
},
},
Validation: tc.routeConfig,
Validation: tc.policyValidation,
},
}
validateBackendTLSPolicy(t, route, tc.wantErrors)
validateBackendTLSPolicy(t, policy, tc.wantErrors)
})
}
}

func validateBackendTLSPolicy(t *testing.T, route *gatewayv1a3.BackendTLSPolicy, wantErrors []string) {
func validateBackendTLSPolicy(t *testing.T, policy *gatewayv1a3.BackendTLSPolicy, wantErrors []string) {
t.Helper()

ctx := context.Background()
err := k8sClient.Create(ctx, route)
err := k8sClient.Create(ctx, policy)

if (len(wantErrors) != 0) != (err != nil) {
t.Fatalf("Unexpected response while creating BackendTLSPolicy %q; got err=\n%v\n;want error=%v", fmt.Sprintf("%v/%v", route.Namespace, route.Name), err, wantErrors)
t.Fatalf("Unexpected response while creating BackendTLSPolicy %q; got err=\n%v\n;want error=%v", fmt.Sprintf("%v/%v", policy.Namespace, policy.Name), err, wantErrors)
}

var missingErrorStrings []string
Expand All @@ -309,6 +490,6 @@ func validateBackendTLSPolicy(t *testing.T, route *gatewayv1a3.BackendTLSPolicy,
}
}
if len(missingErrorStrings) != 0 {
t.Errorf("Unexpected response while creating BackendTLSPolicy %q; got err=\n%v\n;missing strings within error=%q", fmt.Sprintf("%v/%v", route.Namespace, route.Name), err, missingErrorStrings)
t.Errorf("Unexpected response while creating BackendTLSPolicy %q; got err=\n%v\n;missing strings within error=%q", fmt.Sprintf("%v/%v", policy.Namespace, policy.Name), err, missingErrorStrings)
}
}