-
Notifications
You must be signed in to change notification settings - Fork 568
Expand file tree
/
Copy pathno_host_checker.go
More file actions
117 lines (94 loc) · 3.15 KB
/
Copy pathno_host_checker.go
File metadata and controls
117 lines (94 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package authorization
import (
"fmt"
api_security_v1beta "istio.io/api/security/v1beta1"
networking_v1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
security_v1beta "istio.io/client-go/pkg/apis/security/v1beta1"
core_v1 "k8s.io/api/core/v1"
"github.com/kiali/kiali/kubernetes"
"github.com/kiali/kiali/models"
)
type NoHostChecker struct {
AuthorizationPolicy security_v1beta.AuthorizationPolicy
Namespace string
Namespaces models.Namespaces
ServiceEntries map[string][]string
Services []core_v1.Service
VirtualServices []networking_v1alpha3.VirtualService
RegistryStatus []*kubernetes.RegistryStatus
}
func (n NoHostChecker) Check() ([]*models.IstioCheck, bool) {
checks, valid := make([]*models.IstioCheck, 0), true
// Getting rules array. If not present, quitting validation.
if len(n.AuthorizationPolicy.Spec.Rules) == 0 {
return checks, valid
}
// Getting slice of Rules. Quitting if not an slice.
for ruleIdx, rule := range n.AuthorizationPolicy.Spec.Rules {
if rule == nil {
continue
}
if len(rule.To) > 0 {
fromChecks, fromValid := n.validateHost(ruleIdx, rule.To)
checks = append(checks, fromChecks...)
valid = valid && fromValid
}
}
return checks, valid
}
func (n NoHostChecker) validateHost(ruleIdx int, to []*api_security_v1beta.Rule_To) ([]*models.IstioCheck, bool) {
if len(to) == 0 {
return nil, true
}
checks, valid := make([]*models.IstioCheck, 0, len(to)), true
for toIdx, t := range to {
if t == nil {
continue
}
if t.Operation == nil {
continue
}
if len(t.Operation.Hosts) == 0 {
continue
}
for hostIdx, h := range t.Operation.Hosts {
fqdn := kubernetes.GetHost(h, n.AuthorizationPolicy.Namespace, n.AuthorizationPolicy.ClusterName, n.Namespaces.GetNames())
if !n.hasMatchingService(fqdn, n.AuthorizationPolicy.Namespace) {
path := fmt.Sprintf("spec/rules[%d]/to[%d]/operation/hosts[%d]", ruleIdx, toIdx, hostIdx)
validation := models.Build("authorizationpolicy.nodest.matchingregistry", path)
valid = false
checks = append(checks, &validation)
}
}
}
return checks, valid
}
func (n NoHostChecker) hasMatchingService(host kubernetes.Host, itemNamespace string) bool {
// Covering 'servicename.namespace' host format scenario
localSvc, localNs := kubernetes.ParseTwoPartHost(host)
// Check wildcard hosts - needs to match "*" and "*.suffix" also..
if host.IsWildcard() && localNs == itemNamespace {
return true
}
// Only find matches for workloads and services in the same namespace
if localNs == itemNamespace {
// Check ServiceNames
if matches := kubernetes.HasMatchingServices(localSvc, n.Services); matches {
return matches
}
}
// Check ServiceEntries
if kubernetes.HasMatchingServiceEntries(host.String(), n.ServiceEntries) {
return true
}
// Check VirtualServices
if kubernetes.HasMatchingVirtualServices(host, n.VirtualServices) {
return true
}
// Use RegistryStatus to check destinations that may not be covered with previous check
// i.e. Multi-cluster or Federation validations
if kubernetes.HasMatchingRegistryStatus(host.String(), n.RegistryStatus) {
return true
}
return false
}