Egress gtw/connect destination intentions (#13341)

* update gateway-services table with endpoints

* fix failing test

* remove unneeded config in test

* rename "endpoint" to "destination"

* more endpoint renaming to destination in tests

* update isDestination based on service-defaults config entry creation

* use a 3 state kind to be able to set the kind to unknown (when neither a service or a destination exist)

* set unknown state to empty to avoid modifying alot of tests

* fix logic to set the kind correctly on CRUD

* fix failing tests

* add missing tests and fix service delete

* fix failing test

* Apply suggestions from code review

Co-authored-by: Dan Stough <dan.stough@hashicorp.com>

* fix a bug with kind and add relevant test

* fix compile error

* fix failing tests

* add kind to clone

* fix failing tests

* fix failing tests in catalog endpoint

* fix service dump test

* Apply suggestions from code review

Co-authored-by: Dan Stough <dan.stough@hashicorp.com>

* remove duplicate tests

* first draft of destinations intention in connect proxy

* remove ServiceDestinationList

* fix failing tests

* fix agent/consul failing tests

* change to filter intentions in the state store instead of adding a field.

* fix failing tests

* fix comment

* fix comments

* store service kind destination and add relevant tests

* changes based on review

* filter on destinations when querying source match

* Apply suggestions from code review

Co-authored-by: alex <8968914+acpana@users.noreply.github.com>

* fix style

* Apply suggestions from code review

Co-authored-by: Dan Stough <dan.stough@hashicorp.com>

* rename destinationType to targetType.

Co-authored-by: Dan Stough <dan.stough@hashicorp.com>
Co-authored-by: alex <8968914+acpana@users.noreply.github.com>
Co-authored-by: github-team-consul-core <github-team-consul-core@hashicorp.com>
This commit is contained in:
Dhia Ayachi 2022-06-07 15:03:59 -04:00 committed by GitHub
parent dcb511e78a
commit 7602b6ebf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 137 additions and 42 deletions

View file

@ -764,7 +764,7 @@ func (s *Intention) Check(args *structs.IntentionQueryRequest, reply *structs.In
Partition: query.SourcePartition, Partition: query.SourcePartition,
Name: query.SourceName, Name: query.SourceName,
} }
_, intentions, err := store.IntentionMatchOne(nil, entry, structs.IntentionMatchSource) _, intentions, err := store.IntentionMatchOne(nil, entry, structs.IntentionMatchSource, structs.IntentionTargetService)
if err != nil { if err != nil {
return fmt.Errorf("failed to query intentions for %s/%s", query.SourceNS, query.SourceName) return fmt.Errorf("failed to query intentions for %s/%s", query.SourceNS, query.SourceName)
} }

View file

@ -405,7 +405,7 @@ func (m *Internal) GatewayIntentions(args *structs.IntentionQueryRequest, reply
Partition: gs.Service.PartitionOrDefault(), Partition: gs.Service.PartitionOrDefault(),
Name: gs.Service.Name, Name: gs.Service.Name,
} }
idx, intentions, err := state.IntentionMatchOne(ws, entry, structs.IntentionMatchDestination) idx, intentions, err := state.IntentionMatchOne(ws, entry, structs.IntentionMatchDestination, structs.IntentionTargetService)
if err != nil { if err != nil {
return err return err
} }

View file

@ -4009,14 +4009,7 @@ func (s *Store) ServiceTopology(
Partition: entMeta.PartitionOrDefault(), Partition: entMeta.PartitionOrDefault(),
Name: service, Name: service,
} }
_, srcIntentions, err := compatIntentionMatchOneTxn( _, srcIntentions, err := compatIntentionMatchOneTxn(tx, ws, matchEntry, structs.IntentionMatchSource, structs.IntentionTargetService)
tx,
ws,
matchEntry,
// The given service is a source relative to its upstreams
structs.IntentionMatchSource,
)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String()) return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String())
} }
@ -4128,14 +4121,7 @@ func (s *Store) ServiceTopology(
downstreamSources[svc.Name.String()] = source downstreamSources[svc.Name.String()] = source
} }
_, dstIntentions, err := compatIntentionMatchOneTxn( _, dstIntentions, err := compatIntentionMatchOneTxn(tx, ws, matchEntry, structs.IntentionMatchDestination, structs.IntentionTargetService)
tx,
ws,
matchEntry,
// The given service is a destination relative to its downstreams
structs.IntentionMatchDestination,
)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String()) return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String())
} }

View file

@ -356,12 +356,16 @@ func deleteConfigEntryTxn(tx WriteTxn, idx uint64, kind, name string, entMeta *a
if gsKind == structs.GatewayServiceKindDestination { if gsKind == structs.GatewayServiceKindDestination {
gsKind = structs.GatewayServiceKindUnknown gsKind = structs.GatewayServiceKindUnknown
} }
if err := checkGatewayWildcardsAndUpdate(tx, idx, &structs.ServiceName{Name: c.GetName(), EnterpriseMeta: *c.GetEnterpriseMeta()}, gsKind); err != nil { serviceName := structs.NewServiceName(c.GetName(), c.GetEnterpriseMeta())
if err := checkGatewayWildcardsAndUpdate(tx, idx, &serviceName, gsKind); err != nil {
return fmt.Errorf("failed updating gateway mapping: %s", err) return fmt.Errorf("failed updating gateway mapping: %s", err)
} }
if err := checkGatewayAndUpdate(tx, idx, &structs.ServiceName{Name: c.GetName(), EnterpriseMeta: *c.GetEnterpriseMeta()}, gsKind); err != nil { if err := checkGatewayAndUpdate(tx, idx, &serviceName, gsKind); err != nil {
return fmt.Errorf("failed updating gateway mapping: %s", err) return fmt.Errorf("failed updating gateway mapping: %s", err)
} }
if err := cleanupKindServiceName(tx, idx, serviceName, structs.ServiceKindDestination); err != nil {
return fmt.Errorf("failed to cleanup service name: \"%s\"; err: %v", serviceName, err)
}
} }
} }
@ -422,6 +426,10 @@ func insertConfigEntryWithTxn(tx WriteTxn, idx uint64, conf structs.ConfigEntry)
if err := checkGatewayAndUpdate(tx, idx, &sn, gsKind); err != nil { if err := checkGatewayAndUpdate(tx, idx, &sn, gsKind); err != nil {
return fmt.Errorf("failed updating gateway mapping: %s", err) return fmt.Errorf("failed updating gateway mapping: %s", err)
} }
if err := upsertKindServiceName(tx, idx, structs.ServiceKindDestination, sn); err != nil {
return fmt.Errorf("failed to persist service name: %v", err)
}
} }
} }

View file

@ -208,7 +208,7 @@ func (s *Store) configIntentionMatchTxn(tx ReadTxn, ws memdb.WatchSet, args *str
// improving that in the future, the test cases shouldn't have to // improving that in the future, the test cases shouldn't have to
// change for that. // change for that.
index, ixns, err := configIntentionMatchOneTxn(tx, ws, entry, args.Type) index, ixns, err := configIntentionMatchOneTxn(tx, ws, entry, args.Type, structs.IntentionTargetService)
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err
} }
@ -224,14 +224,15 @@ func (s *Store) configIntentionMatchTxn(tx ReadTxn, ws memdb.WatchSet, args *str
} }
func configIntentionMatchOneTxn( func configIntentionMatchOneTxn(
tx ReadTxn, tx ReadTxn, ws memdb.WatchSet,
ws memdb.WatchSet,
matchEntry structs.IntentionMatchEntry, matchEntry structs.IntentionMatchEntry,
matchType structs.IntentionMatchType, matchType structs.IntentionMatchType,
targetType structs.IntentionTargetType,
) (uint64, structs.Intentions, error) { ) (uint64, structs.Intentions, error) {
switch matchType { switch matchType {
// targetType is only relevant for Source matches as egress Destinations can only be Intention Destinations in the mesh
case structs.IntentionMatchSource: case structs.IntentionMatchSource:
return readSourceIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta()) return readSourceIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta(), targetType)
case structs.IntentionMatchDestination: case structs.IntentionMatchDestination:
return readDestinationIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta()) return readDestinationIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta())
default: default:
@ -239,7 +240,13 @@ func configIntentionMatchOneTxn(
} }
} }
func readSourceIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet, serviceName string, entMeta *acl.EnterpriseMeta) (uint64, structs.Intentions, error) { func readSourceIntentionsFromConfigEntriesTxn(
tx ReadTxn,
ws memdb.WatchSet,
serviceName string,
entMeta *acl.EnterpriseMeta,
targetType structs.IntentionTargetType,
) (uint64, structs.Intentions, error) {
idx := maxIndexTxn(tx, tableConfigEntries) idx := maxIndexTxn(tx, tableConfigEntries)
var ( var (
@ -249,9 +256,7 @@ func readSourceIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet, ser
names := getIntentionPrecedenceMatchServiceNames(serviceName, entMeta) names := getIntentionPrecedenceMatchServiceNames(serviceName, entMeta)
for _, sn := range names { for _, sn := range names {
results, err = readSourceIntentionsFromConfigEntriesForServiceTxn( results, err = readSourceIntentionsFromConfigEntriesForServiceTxn(tx, ws, sn.Name, &sn.EnterpriseMeta, results, targetType)
tx, ws, sn.Name, &sn.EnterpriseMeta, results,
)
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err
} }
@ -263,7 +268,14 @@ func readSourceIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet, ser
return idx, results, nil return idx, results, nil
} }
func readSourceIntentionsFromConfigEntriesForServiceTxn(tx ReadTxn, ws memdb.WatchSet, serviceName string, entMeta *acl.EnterpriseMeta, results structs.Intentions) (structs.Intentions, error) { func readSourceIntentionsFromConfigEntriesForServiceTxn(
tx ReadTxn,
ws memdb.WatchSet,
serviceName string,
entMeta *acl.EnterpriseMeta,
results structs.Intentions,
targetType structs.IntentionTargetType,
) (structs.Intentions, error) {
sn := structs.NewServiceName(serviceName, entMeta) sn := structs.NewServiceName(serviceName, entMeta)
iter, err := tx.Get(tableConfigEntries, indexSource, sn) iter, err := tx.Get(tableConfigEntries, indexSource, sn)
@ -276,8 +288,24 @@ func readSourceIntentionsFromConfigEntriesForServiceTxn(tx ReadTxn, ws memdb.Wat
entry := v.(*structs.ServiceIntentionsConfigEntry) entry := v.(*structs.ServiceIntentionsConfigEntry)
for _, src := range entry.Sources { for _, src := range entry.Sources {
if src.SourceServiceName() == sn { if src.SourceServiceName() == sn {
entMeta := entry.DestinationServiceName().EnterpriseMeta
kind, err := GatewayServiceKind(tx, entry.DestinationServiceName().Name, &entMeta)
if err != nil {
return nil, err
}
switch targetType {
case structs.IntentionTargetService:
if kind == structs.GatewayServiceKindService || kind == structs.GatewayServiceKindUnknown {
results = append(results, entry.ToIntention(src)) results = append(results, entry.ToIntention(src))
} }
case structs.IntentionTargetDestination:
if kind == structs.GatewayServiceKindDestination {
results = append(results, entry.ToIntention(src))
}
default:
return nil, fmt.Errorf("invalid target type")
}
}
} }
} }
@ -298,7 +326,6 @@ func readDestinationIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet
results = append(results, entry.ToIntentions()...) results = append(results, entry.ToIntentions()...)
} }
} }
// Sort the results by precedence // Sort the results by precedence
sort.Sort(structs.IntentionPrecedenceSorter(results)) sort.Sort(structs.IntentionPrecedenceSorter(results))

View file

@ -355,6 +355,11 @@ func TestStore_ServiceDefaults_Kind_Destination(t *testing.T) {
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
_, kindServices, err := s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
require.NoError(t, err)
require.Len(t, kindServices, 1)
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
ws = memdb.NewWatchSet() ws = memdb.NewWatchSet()
_, _, err = s.GatewayServices(ws, "Gtwy1", nil) _, _, err = s.GatewayServices(ws, "Gtwy1", nil)
require.NoError(t, err) require.NoError(t, err)
@ -369,6 +374,10 @@ func TestStore_ServiceDefaults_Kind_Destination(t *testing.T) {
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindUnknown) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindUnknown)
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
require.NoError(t, err)
require.Len(t, kindServices, 0)
} }
func TestStore_ServiceDefaults_Kind_NotDestination(t *testing.T) { func TestStore_ServiceDefaults_Kind_NotDestination(t *testing.T) {
@ -475,6 +484,11 @@ func TestStore_Service_TerminatingGateway_Kind_Service_Destination(t *testing.T)
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
_, kindServices, err := s.ServiceNamesOfKind(ws, structs.ServiceKindTypical)
require.NoError(t, err)
require.Len(t, kindServices, 1)
require.Equal(t, kindServices[0].Kind, structs.ServiceKindTypical)
require.NoError(t, s.EnsureConfigEntry(0, destination)) require.NoError(t, s.EnsureConfigEntry(0, destination))
_, gatewayServices, err = s.GatewayServices(nil, "Gtwy1", nil) _, gatewayServices, err = s.GatewayServices(nil, "Gtwy1", nil)
@ -482,6 +496,11 @@ func TestStore_Service_TerminatingGateway_Kind_Service_Destination(t *testing.T)
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindTypical)
require.NoError(t, err)
require.Len(t, kindServices, 1)
require.Equal(t, kindServices[0].Kind, structs.ServiceKindTypical)
ws = memdb.NewWatchSet() ws = memdb.NewWatchSet()
_, _, err = s.GatewayServices(ws, "Gtwy1", nil) _, _, err = s.GatewayServices(ws, "Gtwy1", nil)
require.NoError(t, err) require.NoError(t, err)
@ -496,6 +515,11 @@ func TestStore_Service_TerminatingGateway_Kind_Service_Destination(t *testing.T)
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
require.NoError(t, err)
require.Len(t, kindServices, 1)
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
} }
func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T) { func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T) {
@ -541,6 +565,11 @@ func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T)
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
_, kindServices, err := s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
require.NoError(t, err)
require.Len(t, kindServices, 1)
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
require.NoError(t, s.EnsureNode(0, &structs.Node{Node: "node1"})) require.NoError(t, s.EnsureNode(0, &structs.Node{Node: "node1"}))
require.NoError(t, s.EnsureService(0, "node1", service)) require.NoError(t, s.EnsureService(0, "node1", service))
@ -552,6 +581,11 @@ func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T)
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindTypical)
require.NoError(t, err)
require.Len(t, kindServices, 1)
require.Equal(t, kindServices[0].Kind, structs.ServiceKindTypical)
ws = memdb.NewWatchSet() ws = memdb.NewWatchSet()
_, _, err = s.GatewayServices(ws, "Gtwy1", nil) _, _, err = s.GatewayServices(ws, "Gtwy1", nil)
require.NoError(t, err) require.NoError(t, err)
@ -566,6 +600,11 @@ func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T)
require.Len(t, gatewayServices, 1) require.Len(t, gatewayServices, 1)
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination) require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
require.NoError(t, err)
require.Len(t, kindServices, 1)
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
} }
func TestStore_Service_TerminatingGateway_Kind_Service(t *testing.T) { func TestStore_Service_TerminatingGateway_Kind_Service(t *testing.T) {

View file

@ -600,6 +600,7 @@ func legacyIntentionGetTxn(tx ReadTxn, ws memdb.WatchSet, id string) (uint64, *s
// Convert the interface{} if it is non-nil // Convert the interface{} if it is non-nil
var result *structs.Intention var result *structs.Intention
if intention != nil { if intention != nil {
result = intention.(*structs.Intention) result = intention.(*structs.Intention)
} }
@ -842,11 +843,12 @@ func (s *Store) IntentionMatchOne(
ws memdb.WatchSet, ws memdb.WatchSet,
entry structs.IntentionMatchEntry, entry structs.IntentionMatchEntry,
matchType structs.IntentionMatchType, matchType structs.IntentionMatchType,
destinationType structs.IntentionTargetType,
) (uint64, structs.Intentions, error) { ) (uint64, structs.Intentions, error) {
tx := s.db.Txn(false) tx := s.db.Txn(false)
defer tx.Abort() defer tx.Abort()
return compatIntentionMatchOneTxn(tx, ws, entry, matchType) return compatIntentionMatchOneTxn(tx, ws, entry, matchType, destinationType)
} }
func compatIntentionMatchOneTxn( func compatIntentionMatchOneTxn(
@ -854,6 +856,7 @@ func compatIntentionMatchOneTxn(
ws memdb.WatchSet, ws memdb.WatchSet,
entry structs.IntentionMatchEntry, entry structs.IntentionMatchEntry,
matchType structs.IntentionMatchType, matchType structs.IntentionMatchType,
destinationType structs.IntentionTargetType,
) (uint64, structs.Intentions, error) { ) (uint64, structs.Intentions, error) {
usingConfigEntries, err := areIntentionsInConfigEntries(tx, ws) usingConfigEntries, err := areIntentionsInConfigEntries(tx, ws)
@ -863,7 +866,7 @@ func compatIntentionMatchOneTxn(
if !usingConfigEntries { if !usingConfigEntries {
return legacyIntentionMatchOneTxn(tx, ws, entry, matchType) return legacyIntentionMatchOneTxn(tx, ws, entry, matchType)
} }
return configIntentionMatchOneTxn(tx, ws, entry, matchType) return configIntentionMatchOneTxn(tx, ws, entry, matchType, destinationType)
} }
func legacyIntentionMatchOneTxn( func legacyIntentionMatchOneTxn(
@ -949,8 +952,12 @@ type ServiceWithDecision struct {
// IntentionTopology returns the upstreams or downstreams of a service. Upstreams and downstreams are inferred from // IntentionTopology returns the upstreams or downstreams of a service. Upstreams and downstreams are inferred from
// intentions. If intentions allow a connection from the target to some candidate service, the candidate service is considered // intentions. If intentions allow a connection from the target to some candidate service, the candidate service is considered
// an upstream of the target. // an upstream of the target.
func (s *Store) IntentionTopology(ws memdb.WatchSet, func (s *Store) IntentionTopology(
target structs.ServiceName, downstreams bool, defaultDecision acl.EnforcementDecision) (uint64, structs.ServiceList, error) { ws memdb.WatchSet,
target structs.ServiceName,
downstreams bool,
defaultDecision acl.EnforcementDecision,
) (uint64, structs.ServiceList, error) {
tx := s.db.ReadTxn() tx := s.db.ReadTxn()
defer tx.Abort() defer tx.Abort()
@ -965,13 +972,17 @@ func (s *Store) IntentionTopology(ws memdb.WatchSet,
resp := make(structs.ServiceList, 0) resp := make(structs.ServiceList, 0)
for _, svc := range services { for _, svc := range services {
resp = append(resp, svc.Name) resp = append(resp, structs.ServiceName{Name: svc.Name.Name, EnterpriseMeta: svc.Name.EnterpriseMeta})
} }
return idx, resp, nil return idx, resp, nil
} }
func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet, func (s *Store) intentionTopologyTxn(
target structs.ServiceName, downstreams bool, defaultDecision acl.EnforcementDecision) (uint64, []ServiceWithDecision, error) { tx ReadTxn, ws memdb.WatchSet,
target structs.ServiceName,
downstreams bool,
defaultDecision acl.EnforcementDecision,
) (uint64, []ServiceWithDecision, error) {
var maxIdx uint64 var maxIdx uint64
@ -987,7 +998,7 @@ func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet,
Partition: target.PartitionOrDefault(), Partition: target.PartitionOrDefault(),
Name: target.Name, Name: target.Name,
} }
index, intentions, err := compatIntentionMatchOneTxn(tx, ws, entry, intentionMatchType) index, intentions, err := compatIntentionMatchOneTxn(tx, ws, entry, intentionMatchType, structs.IntentionTargetService)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to query intentions for %s", target.String()) return 0, nil, fmt.Errorf("failed to query intentions for %s", target.String())
} }
@ -1017,6 +1028,16 @@ func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet,
maxIdx = index maxIdx = index
} }
services = append(services, ingress...) services = append(services, ingress...)
} else {
// destinations can only ever be upstream, since they are only allowed as intention destination.
index, destinations, err := serviceNamesOfKindTxn(tx, ws, structs.ServiceKindDestination, *wildcardMeta)
if err != nil {
return index, nil, fmt.Errorf("failed to list destination names: %v", err)
}
if index > maxIdx {
maxIdx = index
}
services = append(services, destinations...)
} }
// When checking authorization to upstreams, the match type for the decision is `destination` because we are deciding // When checking authorization to upstreams, the match type for the decision is `destination` because we are deciding
@ -1056,7 +1077,7 @@ func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet,
} }
result = append(result, ServiceWithDecision{ result = append(result, ServiceWithDecision{
Name: candidate, Name: structs.ServiceName{Name: candidate.Name, EnterpriseMeta: candidate.EnterpriseMeta},
Decision: decision, Decision: decision,
}) })
} }

View file

@ -1533,7 +1533,7 @@ func TestStore_IntentionMatchOne_table(t *testing.T) {
Namespace: "default", Namespace: "default",
Name: query, Name: query,
} }
_, matches, err := s.IntentionMatchOne(nil, entry, typ) _, matches, err := s.IntentionMatchOne(nil, entry, typ, structs.IntentionTargetService)
require.NoError(t, err) require.NoError(t, err)
// Verify matches // Verify matches
@ -1873,7 +1873,7 @@ func TestStore_IntentionDecision(t *testing.T) {
Partition: acl.DefaultPartitionName, Partition: acl.DefaultPartitionName,
Name: tc.src, Name: tc.src,
} }
_, intentions, err := s.IntentionMatchOne(nil, entry, structs.IntentionMatchSource) _, intentions, err := s.IntentionMatchOne(nil, entry, structs.IntentionMatchSource, structs.IntentionTargetService)
if err != nil { if err != nil {
require.NoError(t, err) require.NoError(t, err)
} }

View file

@ -494,6 +494,15 @@ const (
IntentionSourceConsul IntentionSourceType = "consul" IntentionSourceConsul IntentionSourceType = "consul"
) )
type IntentionTargetType string
const (
// IntentionTargetService is a service within the Consul catalog.
IntentionTargetService IntentionTargetType = "service"
// IntentionTargetDestination is a destination defined through a service-default config entry.
IntentionTargetDestination IntentionTargetType = "destination"
)
// Intentions is a list of intentions. // Intentions is a list of intentions.
type Intentions []*Intention type Intentions []*Intention

View file

@ -1178,6 +1178,11 @@ const (
// This service allows external traffic to enter the mesh based on // This service allows external traffic to enter the mesh based on
// centralized configuration. // centralized configuration.
ServiceKindIngressGateway ServiceKind = "ingress-gateway" ServiceKindIngressGateway ServiceKind = "ingress-gateway"
// ServiceKindDestination is a Destination for the Connect feature.
// This service allows external traffic to exit the mesh through a terminating gateway
//based on centralized configuration.
ServiceKindDestination ServiceKind = "destination"
) )
// Type to hold a address and port of a service // Type to hold a address and port of a service