mirror of
https://github.com/traefik/traefik.git
synced 2026-06-17 19:09:29 +03:00
Reject cross-provider references with backendRefs.namespace
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners: # Use GatewayClass defaults for listener definition.
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: http-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- "foo.com"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /bar
|
||||
backendRefs:
|
||||
- weight: 1
|
||||
group: traefik.io
|
||||
kind: TraefikService
|
||||
name: service@file
|
||||
namespace: bar
|
||||
port: 80
|
||||
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
group: ""
|
||||
kind: Service
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners: # Use GatewayClass defaults for listener definition.
|
||||
- name: tcp
|
||||
protocol: TCP
|
||||
port: 9000
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: TCPRoute
|
||||
group: gateway.networking.k8s.io
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
---
|
||||
kind: TCPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1alpha2
|
||||
metadata:
|
||||
name: tcp-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
rules:
|
||||
- backendRefs:
|
||||
- weight: 1
|
||||
group: traefik.io
|
||||
kind: TraefikService
|
||||
name: service@file
|
||||
namespace: bar
|
||||
port: 9000
|
||||
- name: whoamitcp
|
||||
port: 9000
|
||||
weight: 1
|
||||
group: ""
|
||||
kind: Service
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJxRENDQVU2Z0F3SUJBZ0lVWU9zcjBRZ0hPQnE0a1lSQ0w1K1REZFZ0NmJRd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFpYaGhiWEJzWlM1amIyMHdIaGNOTWpVeE1ERXdNRGN4TnpNd1doY05NelV4TURBNApNRGN4TnpNd1dqQVdNUlF3RWdZRFZRUUREQXRsZUdGdGNHeGxMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHClNNNDlBd0VIQTBJQUJET3JpdzNaUTd3SWhXcmJQUzZKRlFUM2JUb05DRjAwdlNWNWZhYjZUYlh5TDh0bHNHcmUKVFJJRjJFd2dzdGVNT2t4R0tLU2xEdnVhRHdxOHAvcVYrMHVqZWpCNE1CMEdBMVVkRGdRV0JCUk1Fa3VleFhRaApVdERnUmcxS0J2NzJDRHErRXpBZkJnTlZIU01FR0RBV2dCUk1Fa3VleFhRaFV0RGdSZzFLQnY3MkNEcStFekFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUNVR0ExVWRFUVFlTUJ5Q0MyVjRZVzF3YkdVdVkyOXRnZzBxTG1WNFlXMXcKYkdVdVkyOXRNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURzODdWazBzd0E2SGdPSmpST3llMW14RDgzcWNHeQpwZUZnb3hWOTNEeStjd0lnVjBNTUVKSmJWc1R5WkszRVErK1hjNXJFTDc4bnJKK1lJRVYrckNVV2o1VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ253Z0w1RFk0VUIxNHNNNmYKRGlrUWR0cWgyUVcxQXJmRjRmYzFVRnppZmRHaFJBTkNBQVF6cTRzTjJVTzhDSVZxMnowdWlSVUU5MjA2RFFoZApOTDBsZVgybStrMjE4aS9MWmJCcTNrMFNCZGhNSUxMWGpEcE1SaWlrcFE3N21nOEt2S2Y2bGZ0TAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
||||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners: # Use GatewayClass defaults for listener definition.
|
||||
- name: tls
|
||||
protocol: TLS
|
||||
port: 9000
|
||||
tls:
|
||||
certificateRefs:
|
||||
- kind: Secret
|
||||
name: supersecret
|
||||
group: ""
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: TLSRoute
|
||||
group: gateway.networking.k8s.io
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
---
|
||||
kind: TLSRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1alpha2
|
||||
metadata:
|
||||
name: tls-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
rules:
|
||||
- backendRefs:
|
||||
- weight: 1
|
||||
group: traefik.io
|
||||
kind: TraefikService
|
||||
name: service@file
|
||||
namespace: bar
|
||||
port: 9000
|
||||
- name: whoamitcp
|
||||
port: 9000
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
@@ -237,6 +237,17 @@ func (p *Provider) loadService(ctx context.Context, listener gatewayListener, co
|
||||
namespace := route.Namespace
|
||||
if backendRef.Namespace != nil && *backendRef.Namespace != "" {
|
||||
namespace = string(*backendRef.Namespace)
|
||||
|
||||
if strings.Contains(string(backendRef.Name), "@") {
|
||||
return provider.Normalize(namespace + "-" + string(backendRef.Name) + "-http"), &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot load HTTPBackendRef %s/%s/%s/%s: namespace is not allowed with a cross-provider reference", group, kind, namespace, backendRef.Name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serviceName := provider.Normalize(namespace + "-" + string(backendRef.Name) + "-http")
|
||||
|
||||
@@ -8366,20 +8366,22 @@ func Test_isCrossProviderNamespaceAllowed(t *testing.T) {
|
||||
func TestCrossProviderNamespaces_HTTPRoute(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
fixture string
|
||||
crossProviderNamespaces []string
|
||||
wantError bool
|
||||
}{
|
||||
{desc: "nil: cross-provider TraefikService backendRefs accepted (backward compatible)", crossProviderNamespaces: nil, wantError: false},
|
||||
{desc: "empty list: cross-provider TraefikService backendRefs are rejected, route dropped", crossProviderNamespaces: []string{}, wantError: true},
|
||||
{desc: "namespace allowed: cross-provider TraefikService backendRefs accepted", crossProviderNamespaces: []string{"default"}, wantError: false},
|
||||
{desc: "namespace not allowed: cross-provider TraefikService backendRefs rejected, route dropped", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
{desc: "nil: cross-provider TraefikService backendRefs accepted (backward compatible)", fixture: "httproute/simple_cross_provider.yml", crossProviderNamespaces: nil, wantError: false},
|
||||
{desc: "empty list: cross-provider TraefikService backendRefs are rejected, route dropped", fixture: "httproute/simple_cross_provider.yml", crossProviderNamespaces: []string{}, wantError: true},
|
||||
{desc: "namespace allowed: cross-provider TraefikService backendRefs accepted", fixture: "httproute/simple_cross_provider.yml", crossProviderNamespaces: []string{"default"}, wantError: false},
|
||||
{desc: "namespace not allowed: cross-provider TraefikService backendRefs rejected, route dropped", fixture: "httproute/simple_cross_provider.yml", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
{desc: "namespace provided with cross-provider backendRef, route dropped", fixture: "httproute/invalid_cross_provider.yml", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
k8sObjects, gwObjects := readResources(t, []string{"services.yml", "httproute/simple_cross_provider.yml"})
|
||||
k8sObjects, gwObjects := readResources(t, []string{"services.yml", test.fixture})
|
||||
|
||||
kubeClient := kubefake.NewClientset(k8sObjects...)
|
||||
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
|
||||
@@ -8429,20 +8431,22 @@ func TestCrossProviderNamespaces_HTTPRoute(t *testing.T) {
|
||||
func TestCrossProviderNamespaces_TCPRoute(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
fixture string
|
||||
crossProviderNamespaces []string
|
||||
wantError bool
|
||||
}{
|
||||
{desc: "nil: cross-provider TraefikService backendRefs accepted (backward compatible)", crossProviderNamespaces: nil, wantError: false},
|
||||
{desc: "empty list: cross-provider TraefikService backendRefs are rejected, route dropped", crossProviderNamespaces: []string{}, wantError: true},
|
||||
{desc: "namespace allowed: cross-provider TraefikService backendRefs accepted", crossProviderNamespaces: []string{"default"}, wantError: false},
|
||||
{desc: "namespace not allowed: cross-provider TraefikService backendRefs rejected, route dropped", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
{desc: "nil: cross-provider TraefikService backendRefs accepted (backward compatible)", fixture: "tcproute/simple_cross_provider.yml", crossProviderNamespaces: nil, wantError: false},
|
||||
{desc: "empty list: cross-provider TraefikService backendRefs are rejected, route dropped", fixture: "tcproute/simple_cross_provider.yml", crossProviderNamespaces: []string{}, wantError: true},
|
||||
{desc: "namespace allowed: cross-provider TraefikService backendRefs accepted", fixture: "tcproute/simple_cross_provider.yml", crossProviderNamespaces: []string{"default"}, wantError: false},
|
||||
{desc: "namespace not allowed: cross-provider TraefikService backendRefs rejected, route dropped", fixture: "tcproute/simple_cross_provider.yml", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
{desc: "namespace provided with cross-provider backendRef, route dropped", fixture: "tcproute/invalid_cross_provider.yml", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
k8sObjects, gwObjects := readResources(t, []string{"services.yml", "tcproute/simple_cross_provider.yml"})
|
||||
k8sObjects, gwObjects := readResources(t, []string{"services.yml", test.fixture})
|
||||
|
||||
kubeClient := kubefake.NewClientset(k8sObjects...)
|
||||
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
|
||||
@@ -8501,20 +8505,22 @@ func TestCrossProviderNamespaces_TCPRoute(t *testing.T) {
|
||||
func TestCrossProviderNamespaces_TLSRoute(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
fixture string
|
||||
crossProviderNamespaces []string
|
||||
wantError bool
|
||||
}{
|
||||
{desc: "nil: cross-provider TraefikService backendRefs accepted (backward compatible)", crossProviderNamespaces: nil, wantError: false},
|
||||
{desc: "empty list: cross-provider TraefikService backendRefs are rejected, route dropped", crossProviderNamespaces: []string{}, wantError: true},
|
||||
{desc: "namespace allowed: cross-provider TraefikService backendRefs accepted", crossProviderNamespaces: []string{"default"}, wantError: false},
|
||||
{desc: "namespace not allowed: cross-provider TraefikService backendRefs rejected, route dropped", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
{desc: "nil: cross-provider TraefikService backendRefs accepted (backward compatible)", fixture: "tlsroute/simple_cross_provider.yml", crossProviderNamespaces: nil, wantError: false},
|
||||
{desc: "empty list: cross-provider TraefikService backendRefs are rejected, route dropped", fixture: "tlsroute/simple_cross_provider.yml", crossProviderNamespaces: []string{}, wantError: true},
|
||||
{desc: "namespace allowed: cross-provider TraefikService backendRefs accepted", fixture: "tlsroute/simple_cross_provider.yml", crossProviderNamespaces: []string{"default"}, wantError: false},
|
||||
{desc: "namespace not allowed: cross-provider TraefikService backendRefs rejected, route dropped", fixture: "tlsroute/simple_cross_provider.yml", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
{desc: "namespace provided with cross-provider backendRef, route dropped", fixture: "tlsroute/invalid_cross_provider.yml", crossProviderNamespaces: []string{"other"}, wantError: true},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
k8sObjects, gwObjects := readResources(t, []string{"services.yml", "tlsroute/simple_cross_provider.yml"})
|
||||
k8sObjects, gwObjects := readResources(t, []string{"services.yml", test.fixture})
|
||||
|
||||
kubeClient := kubefake.NewClientset(k8sObjects...)
|
||||
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
|
||||
|
||||
@@ -221,6 +221,17 @@ func (p *Provider) loadTCPService(route *gatev1alpha2.TCPRoute, backendRef gatev
|
||||
namespace := route.Namespace
|
||||
if backendRef.Namespace != nil && *backendRef.Namespace != "" {
|
||||
namespace = string(*backendRef.Namespace)
|
||||
|
||||
if strings.Contains(string(backendRef.Name), "@") {
|
||||
return provider.Normalize(namespace + "-" + string(backendRef.Name)), nil, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot load TCPRoute BackendRef %s/%s/%s/%s: namespace is not allowed with a cross-provider reference", group, kind, namespace, backendRef.Name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serviceName := provider.Normalize(namespace + "-" + string(backendRef.Name))
|
||||
|
||||
@@ -224,6 +224,17 @@ func (p *Provider) loadTLSService(route *gatev1alpha2.TLSRoute, backendRef gatev
|
||||
namespace := route.Namespace
|
||||
if backendRef.Namespace != nil && *backendRef.Namespace != "" {
|
||||
namespace = string(*backendRef.Namespace)
|
||||
|
||||
if strings.Contains(string(backendRef.Name), "@") {
|
||||
return provider.Normalize(namespace + "-" + string(backendRef.Name)), nil, &metav1.Condition{
|
||||
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||
Status: metav1.ConditionFalse,
|
||||
ObservedGeneration: route.Generation,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(gatev1.RouteReasonRefNotPermitted),
|
||||
Message: fmt.Sprintf("Cannot load TLSRoute BackendRef %s/%s/%s/%s: namespace is not allowed with a cross-provider reference", group, kind, namespace, backendRef.Name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serviceName := provider.Normalize(namespace + "-" + string(backendRef.Name))
|
||||
|
||||
Reference in New Issue
Block a user