github.com/kiali/kiali@v1.84.0/business/checkers/authorization/no_host_checker.go (about)

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