2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2022-07-01 15:15:49 +00:00
|
|
|
package proxycfgglue
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sort"
|
2023-04-20 16:16:04 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/go-memdb"
|
2022-07-01 15:15:49 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/agent/cache"
|
|
|
|
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
2023-04-20 16:16:04 +00:00
|
|
|
"github.com/hashicorp/consul/agent/consul/watch"
|
2022-07-01 15:15:49 +00:00
|
|
|
"github.com/hashicorp/consul/agent/proxycfg"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
2023-04-20 16:16:04 +00:00
|
|
|
"github.com/hashicorp/consul/agent/structs/aclfilter"
|
2022-07-01 15:15:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// CacheIntentions satisfies the proxycfg.Intentions interface by sourcing data
|
|
|
|
// from the agent cache.
|
|
|
|
func CacheIntentions(c *cache.Cache) proxycfg.Intentions {
|
|
|
|
return cacheIntentions{c}
|
|
|
|
}
|
|
|
|
|
|
|
|
type cacheIntentions struct {
|
|
|
|
c *cache.Cache
|
|
|
|
}
|
|
|
|
|
2023-04-20 16:16:04 +00:00
|
|
|
func toIntentionMatchEntry(req *structs.ServiceSpecificRequest) structs.IntentionMatchEntry {
|
|
|
|
return structs.IntentionMatchEntry{
|
|
|
|
Partition: req.PartitionOrDefault(),
|
|
|
|
Namespace: req.NamespaceOrDefault(),
|
|
|
|
Name: req.ServiceName,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-01 15:15:49 +00:00
|
|
|
func (c cacheIntentions) Notify(ctx context.Context, req *structs.ServiceSpecificRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
|
|
|
|
query := &structs.IntentionQueryRequest{
|
|
|
|
Match: &structs.IntentionQueryMatch{
|
2023-04-20 16:16:04 +00:00
|
|
|
Type: structs.IntentionMatchDestination,
|
|
|
|
Entries: []structs.IntentionMatchEntry{toIntentionMatchEntry(req)},
|
2022-07-01 15:15:49 +00:00
|
|
|
},
|
2022-08-02 18:27:34 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Token: req.QueryOptions.Token},
|
2022-07-01 15:15:49 +00:00
|
|
|
}
|
|
|
|
return c.c.NotifyCallback(ctx, cachetype.IntentionMatchName, query, correlationID, func(ctx context.Context, event cache.UpdateEvent) {
|
2022-08-11 09:19:36 +00:00
|
|
|
var result any
|
|
|
|
if event.Err == nil {
|
2022-07-01 15:15:49 +00:00
|
|
|
rsp, ok := event.Result.(*structs.IndexedIntentionMatches)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-04-20 16:16:04 +00:00
|
|
|
var matches structs.SimplifiedIntentions
|
2022-07-01 15:15:49 +00:00
|
|
|
if len(rsp.Matches) != 0 {
|
2023-04-20 16:16:04 +00:00
|
|
|
matches = structs.SimplifiedIntentions(rsp.Matches[0])
|
2022-07-01 15:15:49 +00:00
|
|
|
}
|
2022-08-11 09:19:36 +00:00
|
|
|
result = matches
|
2022-07-01 15:15:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
2022-08-11 09:19:36 +00:00
|
|
|
case ch <- newUpdateEvent(correlationID, result, event.Err):
|
2022-07-01 15:15:49 +00:00
|
|
|
case <-ctx.Done():
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServerIntentions satisfies the proxycfg.Intentions interface by sourcing
|
|
|
|
// data from local materialized views (backed by EventPublisher subscriptions).
|
|
|
|
func ServerIntentions(deps ServerDataSourceDeps) proxycfg.Intentions {
|
|
|
|
return &serverIntentions{deps}
|
|
|
|
}
|
|
|
|
|
|
|
|
type serverIntentions struct {
|
|
|
|
deps ServerDataSourceDeps
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *serverIntentions) Notify(ctx context.Context, req *structs.ServiceSpecificRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
|
2023-04-20 16:16:04 +00:00
|
|
|
return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore,
|
|
|
|
func(ws memdb.WatchSet, store Store) (uint64, structs.SimplifiedIntentions, error) {
|
|
|
|
authz, err := s.deps.ACLResolver.ResolveTokenAndDefaultMeta(req.Token, &req.EnterpriseMeta, nil)
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
2022-07-01 15:15:49 +00:00
|
|
|
}
|
2023-04-20 16:16:04 +00:00
|
|
|
match := toIntentionMatchEntry(req)
|
2022-07-01 15:15:49 +00:00
|
|
|
|
2023-04-20 16:16:04 +00:00
|
|
|
index, ixns, err := store.IntentionMatchOne(ws, match, structs.IntentionMatchDestination, structs.IntentionTargetService)
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
2022-07-01 15:15:49 +00:00
|
|
|
}
|
|
|
|
|
2023-04-20 16:16:04 +00:00
|
|
|
indexedIntentions := &structs.IndexedIntentions{
|
|
|
|
Intentions: structs.Intentions(ixns),
|
|
|
|
}
|
2022-07-01 15:15:49 +00:00
|
|
|
|
2023-04-20 16:16:04 +00:00
|
|
|
aclfilter.New(authz, s.deps.Logger).Filter(indexedIntentions)
|
2022-07-01 15:15:49 +00:00
|
|
|
|
2023-04-20 16:16:04 +00:00
|
|
|
sort.Sort(structs.IntentionPrecedenceSorter(indexedIntentions.Intentions))
|
2022-07-01 15:15:49 +00:00
|
|
|
|
2023-04-20 16:16:04 +00:00
|
|
|
return index, structs.SimplifiedIntentions(indexedIntentions.Intentions), nil
|
2022-07-01 15:15:49 +00:00
|
|
|
},
|
2023-04-20 16:16:04 +00:00
|
|
|
dispatchBlockingQueryUpdate[structs.SimplifiedIntentions](ch),
|
|
|
|
)
|
2022-07-01 15:15:49 +00:00
|
|
|
}
|