APIGW: Routes with duplicate parents should be invalid (#16926)

* ensure route parents are unique when creating an http route

* Ensure tcp route parents are unique

* Added unit tests
This commit is contained in:
John Maguire 2023-04-10 13:20:32 -04:00 committed by GitHub
parent 91fd8b7917
commit 3d11e9b26a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 166 additions and 2 deletions

View File

@ -4,6 +4,7 @@
package structs
import (
"errors"
"fmt"
"strings"
@ -143,10 +144,17 @@ func (e *HTTPRouteConfigEntry) Validate() error {
APIGateway: true,
}
uniques := make(map[ResourceReference]struct{}, len(e.Parents))
for _, parent := range e.Parents {
if !validParentKinds[parent.Kind] {
return fmt.Errorf("unsupported parent kind: %q, must be 'api-gateway'", parent.Kind)
}
if _, ok := uniques[parent]; ok {
return errors.New("route parents must be unique")
}
uniques[parent] = struct{}{}
}
if err := validateConfigEntryMeta(e.Meta); err != nil {
@ -534,10 +542,19 @@ func (e *TCPRouteConfigEntry) Validate() error {
if len(e.Services) > 1 {
return fmt.Errorf("tcp-route currently only supports one service")
}
uniques := make(map[ResourceReference]struct{}, len(e.Parents))
for _, parent := range e.Parents {
if !validParentKinds[parent.Kind] {
return fmt.Errorf("unsupported parent kind: %q, must be 'api-gateway'", parent.Kind)
}
if _, ok := uniques[parent]; ok {
return errors.New("route parents must be unique")
}
uniques[parent] = struct{}{}
}
if err := validateConfigEntryMeta(e.Meta); err != nil {

View File

@ -6,8 +6,9 @@ package structs
import (
"testing"
"github.com/hashicorp/consul/acl"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/acl"
)
func TestTCPRoute(t *testing.T) {
@ -60,6 +61,78 @@ func TestTCPRoute(t *testing.T) {
},
validateErr: "unsupported parent kind",
},
"duplicate parents with no listener specified": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
},
},
},
validateErr: "route parents must be unique",
},
"duplicate parents with listener specified": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
validateErr: "route parents must be unique",
},
"almost duplicate parents with one not specifying a listener": {
entry: &TCPRouteConfigEntry{
Kind: TCPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
check: func(t *testing.T, entry ConfigEntry) {
expectedParents := []ResourceReference{
{
Kind: APIGateway,
Name: "gateway",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
{
Kind: APIGateway,
Name: "gateway",
SectionName: "same",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
}
route := entry.(*TCPRouteConfigEntry)
require.Len(t, route.Parents, 2)
require.Equal(t, expectedParents[0], route.Parents[0])
require.Equal(t, expectedParents[1], route.Parents[1])
},
},
}
testConfigEntryNormalizeAndValidate(t, cases)
}
@ -278,7 +351,8 @@ func TestHTTPRoute(t *testing.T) {
{
Name: "test2",
Weight: -1,
}},
},
},
}},
},
check: func(t *testing.T, entry ConfigEntry) {
@ -287,6 +361,79 @@ func TestHTTPRoute(t *testing.T) {
require.Equal(t, 1, route.Rules[0].Services[1].Weight)
},
},
"duplicate parents with no listener specified": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
},
},
},
validateErr: "route parents must be unique",
},
"duplicate parents with listener specified": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
validateErr: "route parents must be unique",
},
"almost duplicate parents with one not specifying a listener": {
entry: &HTTPRouteConfigEntry{
Kind: HTTPRoute,
Name: "route-two",
Parents: []ResourceReference{
{
Kind: "api-gateway",
Name: "gateway",
},
{
Kind: "api-gateway",
Name: "gateway",
SectionName: "same",
},
},
},
check: func(t *testing.T, entry ConfigEntry) {
expectedParents := []ResourceReference{
{
Kind: APIGateway,
Name: "gateway",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
{
Kind: APIGateway,
Name: "gateway",
SectionName: "same",
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
},
}
route := entry.(*HTTPRouteConfigEntry)
require.Len(t, route.Parents, 2)
require.Equal(t, expectedParents[0], route.Parents[0])
require.Equal(t, expectedParents[1], route.Parents[1])
},
},
}
testConfigEntryNormalizeAndValidate(t, cases)
}