-
Notifications
You must be signed in to change notification settings - Fork 479
/
no_host_checker.go
109 lines (89 loc) · 2.91 KB
/
no_host_checker.go
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
package authorization
import (
"fmt"
api_security_v1beta "istio.io/api/security/v1beta1"
networking_v1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
security_v1beta "istio.io/client-go/pkg/apis/security/v1beta1"
"github.com/kiali/kiali/kubernetes"
"github.com/kiali/kiali/models"
)
type NoHostChecker struct {
AuthorizationPolicy *security_v1beta.AuthorizationPolicy
Namespaces models.Namespaces
ServiceEntries map[string][]string
VirtualServices []*networking_v1beta1.VirtualService
RegistryServices []*kubernetes.RegistryService
PolicyAllowAny bool
}
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
}
namespace := n.AuthorizationPolicy.Namespace
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, namespace, n.Namespaces.GetNames())
if !n.hasMatchingService(fqdn, namespace) {
path := fmt.Sprintf("spec/rules[%d]/to[%d]/operation/hosts[%d]", ruleIdx, toIdx, hostIdx)
validation := models.Build("authorizationpolicy.nodest.matchingregistry", path)
if n.PolicyAllowAny {
validation.Severity = models.WarningSeverity
}
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
_, localNs := kubernetes.ParseTwoPartHost(host)
// Check wildcard hosts - needs to match "*" and "*.suffix" also..
if host.IsWildcard() && localNs == itemNamespace {
return true
}
// Check ServiceEntries
if kubernetes.HasMatchingServiceEntries(host.String(), n.ServiceEntries) {
return true
}
// Check VirtualServices
if kubernetes.HasMatchingVirtualServices(host, n.VirtualServices) {
return true
}
// Use RegistryService to check destinations that may not be covered with previous check
// i.e. Multi-cluster or Federation validations
if kubernetes.HasMatchingRegistryService(itemNamespace, host.String(), n.RegistryServices) {
return true
}
return false
}