2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2022-07-12 10:41:29 +00:00
|
|
|
package proxycfgglue
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/acl"
|
|
|
|
"github.com/hashicorp/consul/agent/consul/state"
|
|
|
|
"github.com/hashicorp/consul/agent/proxycfg"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestServerGatewayServices(t *testing.T) {
|
|
|
|
const index uint64 = 123
|
|
|
|
|
|
|
|
t.Run("ingress gateway", func(t *testing.T) {
|
|
|
|
store := state.NewStateStore(nil)
|
|
|
|
|
|
|
|
authz := policyAuthorizer(t, `
|
|
|
|
service "igw" { policy = "read" }
|
|
|
|
service "web" { policy = "read" }
|
|
|
|
service "db" { policy = "read" }
|
|
|
|
`)
|
|
|
|
|
|
|
|
require.NoError(t, store.EnsureConfigEntry(index, &structs.IngressGatewayConfigEntry{
|
|
|
|
Name: "igw",
|
|
|
|
Listeners: []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Protocol: "tcp",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "web"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Protocol: "tcp",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "db"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Protocol: "tcp",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "no-access"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
dataSource := ServerGatewayServices(ServerDataSourceDeps{
|
|
|
|
ACLResolver: newStaticResolver(authz),
|
|
|
|
GetStore: func() Store { return store },
|
|
|
|
})
|
|
|
|
|
|
|
|
eventCh := make(chan proxycfg.UpdateEvent)
|
|
|
|
require.NoError(t, dataSource.Notify(context.Background(), &structs.ServiceSpecificRequest{ServiceName: "igw"}, "", eventCh))
|
|
|
|
|
|
|
|
testutil.RunStep(t, "initial state", func(t *testing.T) {
|
|
|
|
result := getEventResult[*structs.IndexedGatewayServices](t, eventCh)
|
|
|
|
require.Len(t, result.Services, 2)
|
|
|
|
})
|
|
|
|
|
|
|
|
testutil.RunStep(t, "remove service mapping", func(t *testing.T) {
|
|
|
|
require.NoError(t, store.EnsureConfigEntry(index+1, &structs.IngressGatewayConfigEntry{
|
|
|
|
Name: "igw",
|
|
|
|
Listeners: []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Protocol: "tcp",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "web"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
result := getEventResult[*structs.IndexedGatewayServices](t, eventCh)
|
|
|
|
require.Len(t, result.Services, 1)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("terminating gateway", func(t *testing.T) {
|
|
|
|
store := state.NewStateStore(nil)
|
|
|
|
|
|
|
|
authz := policyAuthorizer(t, `
|
|
|
|
service "tgw" { policy = "read" }
|
|
|
|
service "web" { policy = "read" }
|
|
|
|
service "db" { policy = "read" }
|
|
|
|
`)
|
|
|
|
|
|
|
|
require.NoError(t, store.EnsureConfigEntry(index, &structs.TerminatingGatewayConfigEntry{
|
|
|
|
Name: "tgw",
|
|
|
|
Services: []structs.LinkedService{
|
|
|
|
{Name: "web"},
|
|
|
|
{Name: "db"},
|
|
|
|
{Name: "no-access"},
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
dataSource := ServerGatewayServices(ServerDataSourceDeps{
|
|
|
|
ACLResolver: newStaticResolver(authz),
|
|
|
|
GetStore: func() Store { return store },
|
|
|
|
})
|
|
|
|
|
|
|
|
eventCh := make(chan proxycfg.UpdateEvent)
|
|
|
|
require.NoError(t, dataSource.Notify(context.Background(), &structs.ServiceSpecificRequest{ServiceName: "tgw"}, "", eventCh))
|
|
|
|
|
|
|
|
testutil.RunStep(t, "initial state", func(t *testing.T) {
|
|
|
|
result := getEventResult[*structs.IndexedGatewayServices](t, eventCh)
|
|
|
|
require.Len(t, result.Services, 2)
|
|
|
|
})
|
|
|
|
|
|
|
|
testutil.RunStep(t, "remove service mapping", func(t *testing.T) {
|
|
|
|
require.NoError(t, store.EnsureConfigEntry(index+1, &structs.TerminatingGatewayConfigEntry{
|
|
|
|
Name: "tgw",
|
|
|
|
Services: []structs.LinkedService{
|
|
|
|
{Name: "web"},
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
result := getEventResult[*structs.IndexedGatewayServices](t, eventCh)
|
|
|
|
require.Len(t, result.Services, 1)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("no access to gateway", func(t *testing.T) {
|
|
|
|
store := state.NewStateStore(nil)
|
|
|
|
|
|
|
|
authz := policyAuthorizer(t, `
|
|
|
|
service "tgw" { policy = "deny" }
|
|
|
|
service "web" { policy = "read" }
|
|
|
|
service "db" { policy = "read" }
|
|
|
|
`)
|
|
|
|
|
|
|
|
require.NoError(t, store.EnsureConfigEntry(index, &structs.TerminatingGatewayConfigEntry{
|
|
|
|
Name: "tgw",
|
|
|
|
Services: []structs.LinkedService{
|
|
|
|
{Name: "web"},
|
|
|
|
{Name: "db"},
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
dataSource := ServerGatewayServices(ServerDataSourceDeps{
|
|
|
|
ACLResolver: newStaticResolver(authz),
|
|
|
|
GetStore: func() Store { return store },
|
|
|
|
})
|
|
|
|
|
|
|
|
eventCh := make(chan proxycfg.UpdateEvent)
|
|
|
|
require.NoError(t, dataSource.Notify(context.Background(), &structs.ServiceSpecificRequest{ServiceName: "tgw"}, "", eventCh))
|
|
|
|
|
|
|
|
err := getEventError(t, eventCh)
|
|
|
|
require.True(t, acl.IsErrPermissionDenied(err), "expected permission denied error")
|
|
|
|
})
|
|
|
|
}
|