sync more acl enforcement
sync w ent at 32756f7 Signed-off-by: acpana <8968914+acpana@users.noreply.github.com>
This commit is contained in:
parent
08b94640bc
commit
70e052f35f
|
@ -595,17 +595,15 @@ func (m *Internal) ExportedPeeredServices(args *structs.DCSpecificRequest, reply
|
|||
return err
|
||||
}
|
||||
|
||||
authz, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
|
||||
var authzCtx acl.AuthorizerContext
|
||||
authz, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(peering): acls: mesh gateway needs appropriate wildcard service:read
|
||||
|
||||
return m.srv.blockingQuery(
|
||||
&args.QueryOptions,
|
||||
&reply.QueryMeta,
|
||||
|
@ -632,11 +630,14 @@ func (m *Internal) PeeredUpstreams(args *structs.PartitionSpecificRequest, reply
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO(peering): ACL for filtering
|
||||
// authz, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
var authzCtx acl.AuthorizerContext
|
||||
authz, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := authz.ToAllowAuthorizer().ServiceWriteAnyAllowed(&authzCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
|
||||
return err
|
||||
|
@ -657,9 +658,6 @@ func (m *Internal) PeeredUpstreams(args *structs.PartitionSpecificRequest, reply
|
|||
}
|
||||
|
||||
reply.Index, reply.Services = index, result
|
||||
|
||||
// TODO(peering): low priority: consider ACL filtering
|
||||
// m.srv.filterACLWithAuthorizer(authz, reply)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package consul
|
|||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -3291,3 +3292,193 @@ func TestInternal_ServiceGatewayService_Terminating_Destination(t *testing.T) {
|
|||
assert.Len(t, nodes, 1)
|
||||
assert.Equal(t, expect, nodes)
|
||||
}
|
||||
|
||||
func TestInternal_ExportedPeeredServices_ACLEnforcement(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("too slow for testing.Short")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
_, s := testServerWithConfig(t, testServerACLConfig)
|
||||
codec := rpcClient(t, s)
|
||||
|
||||
require.NoError(t, s.fsm.State().PeeringWrite(1, &pbpeering.Peering{
|
||||
ID: testUUID(),
|
||||
Name: "peer-1",
|
||||
}))
|
||||
require.NoError(t, s.fsm.State().PeeringWrite(1, &pbpeering.Peering{
|
||||
ID: testUUID(),
|
||||
Name: "peer-2",
|
||||
}))
|
||||
require.NoError(t, s.fsm.State().EnsureConfigEntry(1, &structs.ExportedServicesConfigEntry{
|
||||
Name: "default",
|
||||
Services: []structs.ExportedService{
|
||||
{
|
||||
Name: "web",
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{PeerName: "peer-1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "db",
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{PeerName: "peer-2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "api",
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{PeerName: "peer-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
type testcase struct {
|
||||
name string
|
||||
token string
|
||||
expect map[string]structs.ServiceList
|
||||
expectErr string
|
||||
}
|
||||
run := func(t *testing.T, tc testcase) {
|
||||
var out *structs.IndexedExportedServiceList
|
||||
req := structs.DCSpecificRequest{
|
||||
Datacenter: "dc1",
|
||||
QueryOptions: structs.QueryOptions{Token: tc.token},
|
||||
}
|
||||
err := msgpackrpc.CallWithCodec(codec, "Internal.ExportedPeeredServices", &req, &out)
|
||||
|
||||
if tc.expectErr != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tc.expectErr)
|
||||
require.Nil(t, out)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, out.Services, len(tc.expect))
|
||||
for k, v := range tc.expect {
|
||||
require.ElementsMatch(t, v, out.Services[k])
|
||||
}
|
||||
}
|
||||
tcs := []testcase{
|
||||
{
|
||||
name: "can read all",
|
||||
token: tokenWithRules(t, codec, TestDefaultInitialManagementToken,
|
||||
`
|
||||
service_prefix "" {
|
||||
policy = "read"
|
||||
}
|
||||
`),
|
||||
expect: map[string]structs.ServiceList{
|
||||
"peer-1": {
|
||||
structs.NewServiceName("api", nil),
|
||||
structs.NewServiceName("web", nil),
|
||||
},
|
||||
"peer-2": {
|
||||
structs.NewServiceName("db", nil),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filtered",
|
||||
token: tokenWithRules(t, codec, TestDefaultInitialManagementToken,
|
||||
`
|
||||
service "web" { policy = "read" }
|
||||
service "api" { policy = "read" }
|
||||
service "db" { policy = "deny" }
|
||||
`),
|
||||
expect: map[string]structs.ServiceList{
|
||||
"peer-1": {
|
||||
structs.NewServiceName("api", nil),
|
||||
structs.NewServiceName("web", nil),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
run(t, tc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func tokenWithRules(t *testing.T, codec rpc.ClientCodec, mgmtToken, rules string) string {
|
||||
t.Helper()
|
||||
|
||||
var tok *structs.ACLToken
|
||||
var err error
|
||||
retry.Run(t, func(r *retry.R) {
|
||||
tok, err = upsertTestTokenWithPolicyRules(codec, mgmtToken, "dc1", rules)
|
||||
require.NoError(r, err)
|
||||
})
|
||||
return tok.SecretID
|
||||
}
|
||||
|
||||
func TestInternal_PeeredUpstreams_ACLEnforcement(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("too slow for testing.Short")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
_, s := testServerWithConfig(t, testServerACLConfig)
|
||||
codec := rpcClient(t, s)
|
||||
|
||||
type testcase struct {
|
||||
name string
|
||||
token string
|
||||
expectErr string
|
||||
}
|
||||
run := func(t *testing.T, tc testcase) {
|
||||
var out *structs.IndexedPeeredServiceList
|
||||
|
||||
req := structs.PartitionSpecificRequest{
|
||||
Datacenter: "dc1",
|
||||
QueryOptions: structs.QueryOptions{Token: tc.token},
|
||||
}
|
||||
err := msgpackrpc.CallWithCodec(codec, "Internal.PeeredUpstreams", &req, &out)
|
||||
|
||||
if tc.expectErr != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tc.expectErr)
|
||||
require.Nil(t, out)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
tcs := []testcase{
|
||||
{
|
||||
name: "can write all",
|
||||
token: tokenWithRules(t, codec, TestDefaultInitialManagementToken, `
|
||||
service_prefix "" {
|
||||
policy = "write"
|
||||
}
|
||||
`),
|
||||
},
|
||||
{
|
||||
name: "can't write",
|
||||
token: tokenWithRules(t, codec, TestDefaultInitialManagementToken, ``),
|
||||
expectErr: "lacks permission 'service:write' on \"any service\"",
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
run(t, tc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testUUID() string {
|
||||
buf := make([]byte, 16)
|
||||
if _, err := rand.Read(buf); err != nil {
|
||||
panic(fmt.Errorf("failed to read random bytes: %v", err))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
|
||||
buf[0:4],
|
||||
buf[4:6],
|
||||
buf[6:8],
|
||||
buf[8:10],
|
||||
buf[10:16])
|
||||
}
|
||||
|
|
|
@ -3,14 +3,15 @@ package proxycfgglue
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/consul/agent/structs/aclfilter"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/cache"
|
||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||
"github.com/hashicorp/consul/agent/consul/watch"
|
||||
"github.com/hashicorp/consul/agent/proxycfg"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/agent/structs/aclfilter"
|
||||
)
|
||||
|
||||
// CacheExportedPeeredServices satisfies the proxycfg.ExportedPeeredServices
|
||||
|
@ -33,8 +34,8 @@ type serverExportedPeeredServices struct {
|
|||
func (s *serverExportedPeeredServices) Notify(ctx context.Context, req *structs.DCSpecificRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
|
||||
return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore,
|
||||
func(ws memdb.WatchSet, store Store) (uint64, *structs.IndexedExportedServiceList, error) {
|
||||
// TODO(peering): acls: mesh gateway needs appropriate wildcard service:read
|
||||
authz, err := s.deps.ACLResolver.ResolveTokenAndDefaultMeta(req.Token, &req.EnterpriseMeta, nil)
|
||||
var authzCtx acl.AuthorizerContext
|
||||
authz, err := s.deps.ACLResolver.ResolveTokenAndDefaultMeta(req.Token, &req.EnterpriseMeta, &authzCtx)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
|
|
@ -4,13 +4,12 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/consul/agent/consul/state"
|
||||
"github.com/hashicorp/consul/agent/proxycfg"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/proto/pbpeering"
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestServerExportedPeeredServices(t *testing.T) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/go-memdb"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/cache"
|
||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||
"github.com/hashicorp/consul/agent/consul/watch"
|
||||
|
@ -29,9 +30,17 @@ type serverPeeredUpstreams struct {
|
|||
}
|
||||
|
||||
func (s *serverPeeredUpstreams) Notify(ctx context.Context, req *structs.PartitionSpecificRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
|
||||
// TODO(peering): ACL filtering.
|
||||
return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore,
|
||||
func(ws memdb.WatchSet, store Store) (uint64, *structs.IndexedPeeredServiceList, error) {
|
||||
var authzCtx acl.AuthorizerContext
|
||||
authz, err := s.deps.ACLResolver.ResolveTokenAndDefaultMeta(req.Token, &req.EnterpriseMeta, &authzCtx)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if err := authz.ToAllowAuthorizer().ServiceWriteAnyAllowed(&authzCtx); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
index, vips, err := store.VirtualIPsForAllImportedServices(ws, req.EnterpriseMeta)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
|
|
|
@ -14,19 +14,7 @@ import (
|
|||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
)
|
||||
|
||||
func TestServerPeeredUpstreams(t *testing.T) {
|
||||
const (
|
||||
index uint64 = 123
|
||||
nodeName = "node-1"
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
store := state.NewStateStore(nil)
|
||||
enableVirtualIPs(t, store)
|
||||
|
||||
registerService := func(t *testing.T, index uint64, peerName, serviceName string) {
|
||||
func registerService(t *testing.T, index uint64, peerName, serviceName, nodeName string, store *state.Store) {
|
||||
require.NoError(t, store.EnsureRegistration(index, &structs.RegisterRequest{
|
||||
Node: nodeName,
|
||||
Service: &structs.NodeService{Service: serviceName, ID: serviceName},
|
||||
|
@ -48,11 +36,24 @@ func TestServerPeeredUpstreams(t *testing.T) {
|
|||
}))
|
||||
}
|
||||
|
||||
registerService(t, index, "peer-1", "web")
|
||||
func TestServerPeeredUpstreams(t *testing.T) {
|
||||
const (
|
||||
index uint64 = 123
|
||||
nodeName = "node-1"
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
store := state.NewStateStore(nil)
|
||||
enableVirtualIPs(t, store)
|
||||
|
||||
registerService(t, index, "peer-1", "web", nodeName, store)
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
dataSource := ServerPeeredUpstreams(ServerDataSourceDeps{
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(acl.ManageAll()),
|
||||
})
|
||||
require.NoError(t, dataSource.Notify(ctx, &structs.PartitionSpecificRequest{EnterpriseMeta: *acl.DefaultEnterpriseMeta()}, "", eventCh))
|
||||
|
||||
|
@ -64,7 +65,7 @@ func TestServerPeeredUpstreams(t *testing.T) {
|
|||
})
|
||||
|
||||
testutil.RunStep(t, "register another service", func(t *testing.T) {
|
||||
registerService(t, index+1, "peer-2", "db")
|
||||
registerService(t, index+1, "peer-2", "db", nodeName, store)
|
||||
|
||||
result := getEventResult[*structs.IndexedPeeredServiceList](t, eventCh)
|
||||
require.Len(t, result.Services, 2)
|
||||
|
@ -78,6 +79,52 @@ func TestServerPeeredUpstreams(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestServerPeeredUpstreams_ACLEnforcement(t *testing.T) {
|
||||
const (
|
||||
index uint64 = 123
|
||||
nodeName = "node-1"
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
store := state.NewStateStore(nil)
|
||||
enableVirtualIPs(t, store)
|
||||
|
||||
registerService(t, index, "peer-1", "web", nodeName, store)
|
||||
|
||||
testutil.RunStep(t, "read web", func(t *testing.T) {
|
||||
authz := policyAuthorizer(t, `
|
||||
service "web" { policy = "write" }`)
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
dataSource := ServerPeeredUpstreams(ServerDataSourceDeps{
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authz),
|
||||
})
|
||||
require.NoError(t, dataSource.Notify(ctx, &structs.PartitionSpecificRequest{EnterpriseMeta: *acl.DefaultEnterpriseMeta()}, "", eventCh))
|
||||
|
||||
result := getEventResult[*structs.IndexedPeeredServiceList](t, eventCh)
|
||||
require.Len(t, result.Services, 1)
|
||||
require.Equal(t, "peer-1", result.Services[0].Peer)
|
||||
require.Equal(t, "web", result.Services[0].ServiceName.Name)
|
||||
})
|
||||
|
||||
testutil.RunStep(t, "can't read web", func(t *testing.T) {
|
||||
authz := policyAuthorizer(t, ``)
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
dataSource := ServerPeeredUpstreams(ServerDataSourceDeps{
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authz),
|
||||
})
|
||||
require.NoError(t, dataSource.Notify(ctx, &structs.PartitionSpecificRequest{EnterpriseMeta: *acl.DefaultEnterpriseMeta()}, "", eventCh))
|
||||
|
||||
err := getEventError(t, eventCh)
|
||||
require.Contains(t, err.Error(), "lacks permission 'service:write' on \"any service\"")
|
||||
})
|
||||
}
|
||||
|
||||
func enableVirtualIPs(t *testing.T, store *state.Store) {
|
||||
t.Helper()
|
||||
|
||||
|
|
|
@ -33,9 +33,19 @@ type serverTrustBundle struct {
|
|||
}
|
||||
|
||||
func (s *serverTrustBundle) Notify(ctx context.Context, req *cachetype.TrustBundleReadRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
|
||||
// TODO(peering): ACL check.
|
||||
entMeta := structs.NodeEnterpriseMetaInPartition(req.Request.Partition)
|
||||
|
||||
return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore,
|
||||
func(ws memdb.WatchSet, store Store) (uint64, *pbpeering.TrustBundleReadResponse, error) {
|
||||
var authzCtx acl.AuthorizerContext
|
||||
authz, err := s.deps.ACLResolver.ResolveTokenAndDefaultMeta(req.Token, entMeta, &authzCtx)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if err := authz.ToAllowAuthorizer().ServiceWriteAnyAllowed(&authzCtx); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
index, bundle, err := store.PeeringTrustBundleRead(ws, state.Query{
|
||||
Value: req.Request.Name,
|
||||
EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(req.Request.Partition),
|
||||
|
@ -71,13 +81,20 @@ type serverTrustBundleList struct {
|
|||
func (s *serverTrustBundleList) Notify(ctx context.Context, req *cachetype.TrustBundleListRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
|
||||
entMeta := acl.NewEnterpriseMetaWithPartition(req.Request.Partition, req.Request.Namespace)
|
||||
|
||||
// TODO(peering): ACL check.
|
||||
return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore,
|
||||
func(ws memdb.WatchSet, store Store) (uint64, *pbpeering.TrustBundleListByServiceResponse, error) {
|
||||
var authzCtx acl.AuthorizerContext
|
||||
authz, err := s.deps.ACLResolver.ResolveTokenAndDefaultMeta(req.Token, &entMeta, &authzCtx)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if err := authz.ToAllowAuthorizer().ServiceWriteAllowed(req.Request.ServiceName, &authzCtx); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
index uint64
|
||||
bundles []*pbpeering.PeeringTrustBundle
|
||||
err error
|
||||
)
|
||||
switch {
|
||||
case req.Request.Kind == string(structs.ServiceKindMeshGateway):
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
@ -30,6 +31,7 @@ func TestServerTrustBundle(t *testing.T) {
|
|||
|
||||
dataSource := ServerTrustBundle(ServerDataSourceDeps{
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(acl.ManageAll()),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
|
@ -56,6 +58,59 @@ func TestServerTrustBundle(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestServerTrustBundle_ACLEnforcement(t *testing.T) {
|
||||
const (
|
||||
index uint64 = 123
|
||||
peerName = "peer1"
|
||||
)
|
||||
|
||||
store := state.NewStateStore(nil)
|
||||
|
||||
require.NoError(t, store.PeeringTrustBundleWrite(index, &pbpeering.PeeringTrustBundle{
|
||||
PeerName: peerName,
|
||||
TrustDomain: "before.com",
|
||||
}))
|
||||
|
||||
testutil.RunStep(t, "can read", func(t *testing.T) {
|
||||
authz := policyAuthorizer(t, `
|
||||
service "web" { policy = "write" }`)
|
||||
dataSource := ServerTrustBundle(ServerDataSourceDeps{
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authz),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
err := dataSource.Notify(context.Background(), &cachetype.TrustBundleReadRequest{
|
||||
Request: &pbpeering.TrustBundleReadRequest{
|
||||
Name: peerName,
|
||||
},
|
||||
}, "", eventCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
result := getEventResult[*pbpeering.TrustBundleReadResponse](t, eventCh)
|
||||
require.Equal(t, "before.com", result.Bundle.TrustDomain)
|
||||
})
|
||||
|
||||
testutil.RunStep(t, "can't read", func(t *testing.T) {
|
||||
authz := policyAuthorizer(t, ``)
|
||||
dataSource := ServerTrustBundle(ServerDataSourceDeps{
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authz),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
err := dataSource.Notify(context.Background(), &cachetype.TrustBundleReadRequest{
|
||||
Request: &pbpeering.TrustBundleReadRequest{
|
||||
Name: peerName,
|
||||
},
|
||||
}, "", eventCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = getEventError(t, eventCh)
|
||||
require.Contains(t, err.Error(), "provided token lacks permission 'service:write' on \"any service\"")
|
||||
})
|
||||
}
|
||||
|
||||
func TestServerTrustBundleList(t *testing.T) {
|
||||
const index uint64 = 123
|
||||
|
||||
|
@ -96,6 +151,7 @@ func TestServerTrustBundleList(t *testing.T) {
|
|||
dataSource := ServerTrustBundleList(ServerDataSourceDeps{
|
||||
Datacenter: "dc1",
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(acl.ManageAll()),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
|
@ -136,6 +192,7 @@ func TestServerTrustBundleList(t *testing.T) {
|
|||
|
||||
dataSource := ServerTrustBundleList(ServerDataSourceDeps{
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(acl.ManageAll()),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
|
@ -152,6 +209,142 @@ func TestServerTrustBundleList(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestServerTrustBundleList_ACLEnforcement(t *testing.T) {
|
||||
const index uint64 = 123
|
||||
var (
|
||||
authzWriteWeb = policyAuthorizer(t, `service "web" { policy = "write" }`)
|
||||
authzWriteAll = policyAuthorizer(t, `service "" { policy = "write" }`)
|
||||
authzNothing = policyAuthorizer(t, ``)
|
||||
)
|
||||
|
||||
t.Run("ACL enforcement: list by service", func(t *testing.T) {
|
||||
const (
|
||||
serviceName = "web"
|
||||
us = "default"
|
||||
them = "peer2"
|
||||
)
|
||||
|
||||
store := state.NewStateStore(nil)
|
||||
require.NoError(t, store.CASetConfig(index, &structs.CAConfiguration{ClusterID: "cluster-id"}))
|
||||
|
||||
testutil.RunStep(t, "export service to peer", func(t *testing.T) {
|
||||
require.NoError(t, store.PeeringWrite(index, &pbpeering.Peering{
|
||||
ID: testUUID(t),
|
||||
Name: them,
|
||||
State: pbpeering.PeeringState_ACTIVE,
|
||||
}))
|
||||
|
||||
require.NoError(t, store.PeeringTrustBundleWrite(index, &pbpeering.PeeringTrustBundle{
|
||||
PeerName: them,
|
||||
}))
|
||||
|
||||
require.NoError(t, store.EnsureConfigEntry(index, &structs.ExportedServicesConfigEntry{
|
||||
Name: us,
|
||||
Services: []structs.ExportedService{
|
||||
{
|
||||
Name: serviceName,
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{PeerName: them},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
testutil.RunStep(t, "can read", func(t *testing.T) {
|
||||
dataSource := ServerTrustBundleList(ServerDataSourceDeps{
|
||||
Datacenter: "dc1",
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authzWriteWeb),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
err := dataSource.Notify(context.Background(), &cachetype.TrustBundleListRequest{
|
||||
Request: &pbpeering.TrustBundleListByServiceRequest{
|
||||
ServiceName: serviceName,
|
||||
Partition: us,
|
||||
},
|
||||
}, "", eventCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
result := getEventResult[*pbpeering.TrustBundleListByServiceResponse](t, eventCh)
|
||||
require.Len(t, result.Bundles, 1)
|
||||
})
|
||||
|
||||
testutil.RunStep(t, "can't read", func(t *testing.T) {
|
||||
dataSource := ServerTrustBundleList(ServerDataSourceDeps{
|
||||
Datacenter: "dc1",
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authzNothing),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
err := dataSource.Notify(context.Background(), &cachetype.TrustBundleListRequest{
|
||||
Request: &pbpeering.TrustBundleListByServiceRequest{
|
||||
ServiceName: serviceName,
|
||||
Partition: us,
|
||||
},
|
||||
}, "", eventCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = getEventError(t, eventCh)
|
||||
require.Contains(t, err.Error(), "provided token lacks permission 'service:write' on \"web\"")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("ACL Enforcement: list for mesh gateway", func(t *testing.T) {
|
||||
store := state.NewStateStore(nil)
|
||||
require.NoError(t, store.CASetConfig(index, &structs.CAConfiguration{ClusterID: "cluster-id"}))
|
||||
|
||||
require.NoError(t, store.PeeringTrustBundleWrite(index, &pbpeering.PeeringTrustBundle{
|
||||
PeerName: "peer1",
|
||||
}))
|
||||
require.NoError(t, store.PeeringTrustBundleWrite(index, &pbpeering.PeeringTrustBundle{
|
||||
PeerName: "peer2",
|
||||
}))
|
||||
|
||||
testutil.RunStep(t, "can read", func(t *testing.T) {
|
||||
dataSource := ServerTrustBundleList(ServerDataSourceDeps{
|
||||
Datacenter: "dc1",
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authzWriteAll),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
err := dataSource.Notify(context.Background(), &cachetype.TrustBundleListRequest{
|
||||
Request: &pbpeering.TrustBundleListByServiceRequest{
|
||||
Kind: string(structs.ServiceKindMeshGateway),
|
||||
Partition: "default",
|
||||
},
|
||||
}, "", eventCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
result := getEventResult[*pbpeering.TrustBundleListByServiceResponse](t, eventCh)
|
||||
require.Len(t, result.Bundles, 2)
|
||||
})
|
||||
|
||||
testutil.RunStep(t, "can't read", func(t *testing.T) {
|
||||
dataSource := ServerTrustBundleList(ServerDataSourceDeps{
|
||||
Datacenter: "dc1",
|
||||
GetStore: func() Store { return store },
|
||||
ACLResolver: newStaticResolver(authzNothing),
|
||||
})
|
||||
|
||||
eventCh := make(chan proxycfg.UpdateEvent)
|
||||
err := dataSource.Notify(context.Background(), &cachetype.TrustBundleListRequest{
|
||||
Request: &pbpeering.TrustBundleListByServiceRequest{
|
||||
Kind: string(structs.ServiceKindMeshGateway),
|
||||
Partition: "default",
|
||||
},
|
||||
}, "", eventCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = getEventError(t, eventCh)
|
||||
require.Contains(t, err.Error(), "provided token lacks permission 'service:write'")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func testUUID(t *testing.T) string {
|
||||
v, err := lib.GenerateUUID(nil)
|
||||
require.NoError(t, err)
|
||||
|
|
Loading…
Reference in New Issue