2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-28 18:39:22 +00:00
|
|
|
|
2022-07-01 15:18:33 +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"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestServerIntentionUpstreams(t *testing.T) {
|
|
|
|
const serviceName = "web"
|
|
|
|
|
|
|
|
var index uint64
|
|
|
|
getIndex := func() uint64 {
|
|
|
|
index++
|
|
|
|
return index
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
store := state.NewStateStore(nil)
|
|
|
|
disableLegacyIntentions(t, store)
|
|
|
|
|
|
|
|
// Register api and db services.
|
|
|
|
for _, service := range []string{"api", "db"} {
|
|
|
|
err := store.EnsureRegistration(getIndex(), &structs.RegisterRequest{
|
|
|
|
Node: "node-1",
|
|
|
|
Service: &structs.NodeService{
|
|
|
|
Service: service,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
createIntention := func(destination string) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
err := store.EnsureConfigEntry(getIndex(), &structs.ServiceIntentionsConfigEntry{
|
|
|
|
Name: destination,
|
|
|
|
Sources: []*structs.SourceIntention{
|
|
|
|
{
|
|
|
|
Name: serviceName,
|
|
|
|
Action: structs.IntentionActionAllow,
|
|
|
|
Type: structs.IntentionSourceConsul,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an allow intention for the api service. This should be filtered out
|
|
|
|
// because the ACL token doesn't have read access on it.
|
|
|
|
createIntention("api")
|
|
|
|
|
|
|
|
authz := policyAuthorizer(t, `service "db" { policy = "read" }`)
|
|
|
|
|
|
|
|
dataSource := ServerIntentionUpstreams(ServerDataSourceDeps{
|
2022-07-12 10:34:14 +00:00
|
|
|
ACLResolver: newStaticResolver(authz),
|
2022-07-01 15:18:33 +00:00
|
|
|
GetStore: func() Store { return store },
|
2024-02-08 20:25:42 +00:00
|
|
|
}, "")
|
2022-07-01 15:18:33 +00:00
|
|
|
|
|
|
|
ch := make(chan proxycfg.UpdateEvent)
|
|
|
|
err := dataSource.Notify(ctx, &structs.ServiceSpecificRequest{ServiceName: serviceName}, "", ch)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-12 10:34:14 +00:00
|
|
|
result := getEventResult[*structs.IndexedServiceList](t, ch)
|
|
|
|
require.Len(t, result.Services, 0)
|
2022-07-01 15:18:33 +00:00
|
|
|
|
|
|
|
// Create an allow intention for the db service. This should *not* be filtered
|
|
|
|
// out because the ACL token *does* have read access on it.
|
|
|
|
createIntention("db")
|
|
|
|
|
2022-07-12 10:34:14 +00:00
|
|
|
result = getEventResult[*structs.IndexedServiceList](t, ch)
|
|
|
|
require.Len(t, result.Services, 1)
|
|
|
|
require.Equal(t, "db", result.Services[0].Name)
|
2022-07-01 15:18:33 +00:00
|
|
|
}
|
|
|
|
|
2024-02-08 20:25:42 +00:00
|
|
|
// Variant of TestServerIntentionUpstreams where a default allow intention policy
|
|
|
|
// returns "db" service as an IntentionUpstream even if there are no explicit
|
|
|
|
// intentions for "db".
|
|
|
|
func TestServerIntentionUpstreams_DefaultIntentionPolicy(t *testing.T) {
|
|
|
|
const serviceName = "web"
|
|
|
|
|
|
|
|
var index uint64
|
|
|
|
getIndex := func() uint64 {
|
|
|
|
index++
|
|
|
|
return index
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
store := state.NewStateStore(nil)
|
|
|
|
disableLegacyIntentions(t, store)
|
|
|
|
|
|
|
|
require.NoError(t, store.EnsureRegistration(getIndex(), &structs.RegisterRequest{
|
|
|
|
Node: "node-1",
|
|
|
|
Service: &structs.NodeService{
|
|
|
|
Service: "db",
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
// Ensures that "db" service will not be filtered due to ACLs
|
|
|
|
authz := policyAuthorizer(t, `service "db" { policy = "read" }`)
|
|
|
|
|
|
|
|
dataSource := ServerIntentionUpstreams(ServerDataSourceDeps{
|
|
|
|
ACLResolver: newStaticResolver(authz),
|
|
|
|
GetStore: func() Store { return store },
|
|
|
|
}, "allow")
|
|
|
|
|
|
|
|
ch := make(chan proxycfg.UpdateEvent)
|
|
|
|
require.NoError(t, dataSource.Notify(ctx, &structs.ServiceSpecificRequest{ServiceName: serviceName}, "", ch))
|
|
|
|
|
|
|
|
result := getEventResult[*structs.IndexedServiceList](t, ch)
|
|
|
|
require.Len(t, result.Services, 1)
|
|
|
|
require.Equal(t, "db", result.Services[0].Name)
|
|
|
|
}
|
|
|
|
|
2022-07-01 15:18:33 +00:00
|
|
|
func disableLegacyIntentions(t *testing.T, store *state.Store) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
require.NoError(t, store.SystemMetadataSet(0, &structs.SystemMetadataEntry{
|
|
|
|
Key: structs.SystemMetadataIntentionFormatKey,
|
|
|
|
Value: structs.SystemMetadataIntentionFormatConfigValue,
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
func policyAuthorizer(t *testing.T, policyHCL string) acl.Authorizer {
|
2023-02-06 15:35:52 +00:00
|
|
|
policy, err := acl.NewPolicyFromSource(policyHCL, nil, nil)
|
2022-07-01 15:18:33 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
authz, err := acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{policy}, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return authz
|
|
|
|
}
|