Files
tailscale/cmd/k8s-operator/e2e/proxygrouppolicy_test.go
Brad Fitzpatrick 2a64c03c95 types/ptr: deprecate ptr.To, use Go 1.26 new
Updates #18682

Change-Id: I62f6aa0de2a15ef8c1435032c6aa74a181c25f8f
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-03-05 20:13:18 -08:00

161 lines
4.3 KiB
Go

// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
package e2e
import (
"strings"
"testing"
"time"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
)
// See [TestMain] for test requirements.
func TestProxyGroupPolicy(t *testing.T) {
if tnClient == nil {
t.Skip("TestProxyGroupPolicy requires a working tailnet client")
}
// Apply deny-all policy
denyAllPolicy := &tsapi.ProxyGroupPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "deny-all",
Namespace: metav1.NamespaceDefault,
},
Spec: tsapi.ProxyGroupPolicySpec{
Ingress: []string{},
Egress: []string{},
},
}
createAndCleanup(t, kubeClient, denyAllPolicy)
<-time.After(time.Second * 2)
// Attempt to create an egress Service within the default namespace, the above policy should
// reject it.
egressService := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "egress-to-proxy-group",
Namespace: metav1.NamespaceDefault,
Annotations: map[string]string{
"tailscale.com/tailnet-fqdn": "test.something.ts.net",
"tailscale.com/proxy-group": "test",
},
},
Spec: corev1.ServiceSpec{
ExternalName: "placeholder",
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
Port: 8080,
Protocol: corev1.ProtocolTCP,
Name: "http",
},
},
},
}
err := createAndCleanupErr(t, kubeClient, egressService)
switch {
case err != nil && strings.Contains(err.Error(), "ValidatingAdmissionPolicy"):
case err != nil:
t.Fatalf("expected forbidden error, got: %v", err)
default:
t.Fatal("expected error when creating egress service")
}
// Attempt to create an ingress Service within the default namespace, the above policy should
// reject it.
ingressService := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-to-proxy-group",
Namespace: metav1.NamespaceDefault,
Annotations: map[string]string{
"tailscale.com/proxy-group": "test",
},
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
LoadBalancerClass: new("tailscale"),
Ports: []corev1.ServicePort{
{
Port: 8080,
Protocol: corev1.ProtocolTCP,
Name: "http",
},
},
},
}
err = createAndCleanupErr(t, kubeClient, ingressService)
switch {
case err != nil && strings.Contains(err.Error(), "ValidatingAdmissionPolicy"):
case err != nil:
t.Fatalf("expected forbidden error, got: %v", err)
default:
t.Fatal("expected error when creating ingress service")
}
// Attempt to create an Ingress within the default namespace, the above policy should reject it
ingress := &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-to-proxy-group",
Namespace: metav1.NamespaceDefault,
Annotations: map[string]string{
"tailscale.com/proxy-group": "test",
},
},
Spec: networkingv1.IngressSpec{
IngressClassName: new("tailscale"),
DefaultBackend: &networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "nginx",
Port: networkingv1.ServiceBackendPort{
Number: 80,
},
},
},
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"nginx"},
},
},
},
}
err = createAndCleanupErr(t, kubeClient, ingress)
switch {
case err != nil && strings.Contains(err.Error(), "ValidatingAdmissionPolicy"):
case err != nil:
t.Fatalf("expected forbidden error, got: %v", err)
default:
t.Fatal("expected error when creating ingress")
}
// Add policy to allow ingress/egress using the "test" proxy-group. This should be merged with the deny-all
// policy so they do not conflict.
allowTestPolicy := &tsapi.ProxyGroupPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "allow-test",
Namespace: metav1.NamespaceDefault,
},
Spec: tsapi.ProxyGroupPolicySpec{
Ingress: []string{"test"},
Egress: []string{"test"},
},
}
createAndCleanup(t, kubeClient, allowTestPolicy)
<-time.After(time.Second * 2)
// With this policy in place, the above ingress/egress resources should be allowed to be created.
createAndCleanup(t, kubeClient, egressService)
createAndCleanup(t, kubeClient, ingressService)
createAndCleanup(t, kubeClient, ingress)
}