Include virtual services from discovery chain in intention topology (#16862)
This commit is contained in:
parent
29daa2f054
commit
dee8609793
|
@ -3039,6 +3039,30 @@ func (s *Store) VirtualIPForService(psn structs.PeeredServiceName) (string, erro
|
||||||
return result.String(), nil
|
return result.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) ServiceVirtualIPs() (uint64, []ServiceVirtualIP, error) {
|
||||||
|
tx := s.db.Txn(false)
|
||||||
|
defer tx.Abort()
|
||||||
|
|
||||||
|
return servicesVirtualIPsTxn(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func servicesVirtualIPsTxn(tx ReadTxn) (uint64, []ServiceVirtualIP, error) {
|
||||||
|
iter, err := tx.Get(tableServiceVirtualIPs, indexID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var vips []ServiceVirtualIP
|
||||||
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
||||||
|
vip := raw.(ServiceVirtualIP)
|
||||||
|
vips = append(vips, vip)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := maxIndexWatchTxn(tx, nil, tableServiceVirtualIPs)
|
||||||
|
|
||||||
|
return idx, vips, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) ServiceManualVIPs(psn structs.PeeredServiceName) (*ServiceVirtualIP, error) {
|
func (s *Store) ServiceManualVIPs(psn structs.PeeredServiceName) (*ServiceVirtualIP, error) {
|
||||||
tx := s.db.Txn(false)
|
tx := s.db.Txn(false)
|
||||||
defer tx.Abort()
|
defer tx.Abort()
|
||||||
|
|
|
@ -1063,12 +1063,40 @@ func (s *Store) intentionTopologyTxn(
|
||||||
// Ideally those should be excluded as well, since they can't be upstreams/downstreams without a proxy.
|
// Ideally those should be excluded as well, since they can't be upstreams/downstreams without a proxy.
|
||||||
// Maybe narrow serviceNamesOfKindTxn to services represented by proxies? (ingress, sidecar-
|
// Maybe narrow serviceNamesOfKindTxn to services represented by proxies? (ingress, sidecar-
|
||||||
wildcardMeta := structs.WildcardEnterpriseMetaInPartition(structs.WildcardSpecifier)
|
wildcardMeta := structs.WildcardEnterpriseMetaInPartition(structs.WildcardSpecifier)
|
||||||
var services []*KindServiceName
|
|
||||||
|
services := make(map[structs.ServiceName]struct{})
|
||||||
|
addSvcs := func(svcs []*KindServiceName) {
|
||||||
|
for _, s := range svcs {
|
||||||
|
services[s.Service] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tempServices []*KindServiceName
|
||||||
if intentionTarget == structs.IntentionTargetService {
|
if intentionTarget == structs.IntentionTargetService {
|
||||||
index, services, err = serviceNamesOfKindTxn(tx, ws, structs.ServiceKindTypical, *wildcardMeta)
|
index, tempServices, err = serviceNamesOfKindTxn(tx, ws, structs.ServiceKindTypical, *wildcardMeta)
|
||||||
|
if err != nil {
|
||||||
|
return index, nil, fmt.Errorf("failed to list service names: %v", err)
|
||||||
|
}
|
||||||
|
addSvcs(tempServices)
|
||||||
|
|
||||||
|
// Query the virtual ip table as well to include virtual services that don't have a registered instance yet.
|
||||||
|
vipIndex, vipServices, err := servicesVirtualIPsTxn(tx)
|
||||||
|
if err != nil {
|
||||||
|
return index, nil, fmt.Errorf("failed to list service virtual IPs: %v", err)
|
||||||
|
}
|
||||||
|
for _, svc := range vipServices {
|
||||||
|
services[svc.Service.ServiceName] = struct{}{}
|
||||||
|
}
|
||||||
|
if vipIndex > index {
|
||||||
|
index = vipIndex
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// destinations can only ever be upstream, since they are only allowed as intention destination.
|
// destinations can only ever be upstream, since they are only allowed as intention destination.
|
||||||
index, services, err = serviceNamesOfKindTxn(tx, ws, structs.ServiceKindDestination, *wildcardMeta)
|
index, tempServices, err = serviceNamesOfKindTxn(tx, ws, structs.ServiceKindDestination, *wildcardMeta)
|
||||||
|
if err != nil {
|
||||||
|
return index, nil, fmt.Errorf("failed to list destination service names: %v", err)
|
||||||
|
}
|
||||||
|
addSvcs(tempServices)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return index, nil, fmt.Errorf("failed to list ingress service names: %v", err)
|
return index, nil, fmt.Errorf("failed to list ingress service names: %v", err)
|
||||||
|
@ -1086,7 +1114,7 @@ func (s *Store) intentionTopologyTxn(
|
||||||
if index > maxIdx {
|
if index > maxIdx {
|
||||||
maxIdx = index
|
maxIdx = index
|
||||||
}
|
}
|
||||||
services = append(services, ingress...)
|
addSvcs(ingress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -1097,8 +1125,7 @@ func (s *Store) intentionTopologyTxn(
|
||||||
decisionMatchType = structs.IntentionMatchSource
|
decisionMatchType = structs.IntentionMatchSource
|
||||||
}
|
}
|
||||||
result := make([]ServiceWithDecision, 0, len(services))
|
result := make([]ServiceWithDecision, 0, len(services))
|
||||||
for _, svc := range services {
|
for candidate := range services {
|
||||||
candidate := svc.Service
|
|
||||||
if candidate.Name == structs.ConsulServiceName {
|
if candidate.Name == structs.ConsulServiceName {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -2161,6 +2161,7 @@ func TestStore_IntentionTopology(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
defaultDecision acl.EnforcementDecision
|
defaultDecision acl.EnforcementDecision
|
||||||
intentions []structs.ServiceIntentionsConfigEntry
|
intentions []structs.ServiceIntentionsConfigEntry
|
||||||
|
discoveryChains []structs.ConfigEntry
|
||||||
target structs.ServiceName
|
target structs.ServiceName
|
||||||
downstreams bool
|
downstreams bool
|
||||||
expect expect
|
expect expect
|
||||||
|
@ -2192,6 +2193,68 @@ func TestStore_IntentionTopology(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "(upstream) acl allow includes virtual service",
|
||||||
|
defaultDecision: acl.Allow,
|
||||||
|
discoveryChains: []structs.ConfigEntry{
|
||||||
|
&structs.ServiceResolverConfigEntry{
|
||||||
|
Kind: structs.ServiceResolver,
|
||||||
|
Name: "backend",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target: structs.NewServiceName("web", nil),
|
||||||
|
downstreams: false,
|
||||||
|
expect: expect{
|
||||||
|
idx: 10,
|
||||||
|
services: structs.ServiceList{
|
||||||
|
{
|
||||||
|
Name: "api",
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "backend",
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "mysql",
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "(upstream) acl deny all intentions allow virtual service",
|
||||||
|
defaultDecision: acl.Deny,
|
||||||
|
discoveryChains: []structs.ConfigEntry{
|
||||||
|
&structs.ServiceResolverConfigEntry{
|
||||||
|
Kind: structs.ServiceResolver,
|
||||||
|
Name: "backend",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
intentions: []structs.ServiceIntentionsConfigEntry{
|
||||||
|
{
|
||||||
|
Kind: structs.ServiceIntentions,
|
||||||
|
Name: "backend",
|
||||||
|
Sources: []*structs.SourceIntention{
|
||||||
|
{
|
||||||
|
Name: "web",
|
||||||
|
Action: structs.IntentionActionAllow,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target: structs.NewServiceName("web", nil),
|
||||||
|
downstreams: false,
|
||||||
|
expect: expect{
|
||||||
|
idx: 11,
|
||||||
|
services: structs.ServiceList{
|
||||||
|
{
|
||||||
|
Name: "backend",
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "(upstream) acl deny all intentions allow one",
|
name: "(upstream) acl deny all intentions allow one",
|
||||||
defaultDecision: acl.Deny,
|
defaultDecision: acl.Deny,
|
||||||
|
@ -2378,6 +2441,10 @@ func TestStore_IntentionTopology(t *testing.T) {
|
||||||
require.NoError(t, s.EnsureConfigEntry(idx, &ixn))
|
require.NoError(t, s.EnsureConfigEntry(idx, &ixn))
|
||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
|
for _, entry := range tt.discoveryChains {
|
||||||
|
require.NoError(t, s.EnsureConfigEntry(idx, entry))
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
idx, got, err := s.IntentionTopology(nil, tt.target, tt.downstreams, tt.defaultDecision, structs.IntentionTargetService)
|
idx, got, err := s.IntentionTopology(nil, tt.target, tt.downstreams, tt.defaultDecision, structs.IntentionTargetService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
Loading…
Reference in New Issue