github.com/kiali/kiali@v1.84.0/business/checkers/authorization/mtls_enabled_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  	"k8s.io/apimachinery/pkg/labels"
    11  
    12  	"github.com/kiali/kiali/kubernetes"
    13  	"github.com/kiali/kiali/models"
    14  	"github.com/kiali/kiali/util/mtls"
    15  )
    16  
    17  const objectType = "authorizationpolicy"
    18  
    19  type MtlsEnabledChecker struct {
    20  	AuthorizationPolicies []*security_v1beta.AuthorizationPolicy
    21  	MtlsDetails           kubernetes.MTLSDetails
    22  	ServiceEntries        []networking_v1beta1.ServiceEntry
    23  	RegistryServices      []*kubernetes.RegistryService
    24  }
    25  
    26  // Checks if mTLS is enabled, mark all Authz Policies with error
    27  func (c MtlsEnabledChecker) Check() models.IstioValidations {
    28  	validations := models.IstioValidations{}
    29  
    30  	for _, ap := range c.AuthorizationPolicies {
    31  		matchLabels := map[string]string{}
    32  		if ap.Spec.Selector != nil {
    33  			matchLabels = ap.Spec.Selector.MatchLabels
    34  		}
    35  		receiveMtlsTraffic := c.IsMtlsEnabledFor(matchLabels, ap.Namespace)
    36  		if !receiveMtlsTraffic {
    37  			if need, paths := needsMtls(ap); need {
    38  				checks := make([]*models.IstioCheck, 0)
    39  				key := models.BuildKey(objectType, ap.Name, ap.Namespace)
    40  
    41  				for _, path := range paths {
    42  					check := models.Build("authorizationpolicy.mtls.needstobeenabled", path)
    43  					checks = append(checks, &check)
    44  				}
    45  
    46  				validations.MergeValidations(models.IstioValidations{key: &models.IstioValidation{
    47  					Name:       ap.Namespace,
    48  					ObjectType: objectType,
    49  					Valid:      false,
    50  					Checks:     checks,
    51  				}})
    52  			}
    53  		}
    54  	}
    55  
    56  	return validations
    57  }
    58  
    59  func needsMtls(ap *security_v1beta.AuthorizationPolicy) (bool, []string) {
    60  	paths := make([]string, 0)
    61  	if len(ap.Spec.Rules) == 0 {
    62  		return false, nil
    63  	}
    64  
    65  	for i, rule := range ap.Spec.Rules {
    66  		if rule == nil {
    67  			continue
    68  		}
    69  		if needs, fPaths := fromNeedsMtls(rule.From, i); needs {
    70  			paths = append(paths, fPaths...)
    71  		}
    72  		if needs, cPaths := conditionNeedsMtls(rule.When, i); needs {
    73  			paths = append(paths, cPaths...)
    74  		}
    75  	}
    76  	return len(paths) > 0, paths
    77  }
    78  
    79  func fromNeedsMtls(froms []*api_security_v1beta.Rule_From, ruleNum int) (bool, []string) {
    80  	paths := make([]string, 0)
    81  
    82  	for _, from := range froms {
    83  		if from == nil {
    84  			continue
    85  		}
    86  
    87  		if from.Source == nil {
    88  			continue
    89  		}
    90  
    91  		if len(from.Source.Principals) > 0 {
    92  			paths = append(paths, fmt.Sprintf("spec/rules[%d]/source/principals", ruleNum))
    93  		}
    94  		if len(from.Source.NotPrincipals) > 0 {
    95  			paths = append(paths, fmt.Sprintf("spec/rules[%d]/source/notPrincipals", ruleNum))
    96  		}
    97  		if len(from.Source.Namespaces) > 0 {
    98  			paths = append(paths, fmt.Sprintf("spec/rules[%d]/source/namespaces", ruleNum))
    99  		}
   100  		if len(from.Source.NotNamespaces) > 0 {
   101  			paths = append(paths, fmt.Sprintf("spec/rules[%d]/source/notNamespaces", ruleNum))
   102  		}
   103  	}
   104  	return len(paths) > 0, paths
   105  }
   106  
   107  func conditionNeedsMtls(conditions []*api_security_v1beta.Condition, ruleNum int) (bool, []string) {
   108  	var keysWithMtls = [3]string{"source.namespace", "source.principal", "connection.sni"}
   109  	paths := make([]string, 0)
   110  
   111  	for i, c := range conditions {
   112  		if c == nil {
   113  			continue
   114  		}
   115  		for _, key := range keysWithMtls {
   116  			if c.Key == key {
   117  				paths = append(paths, fmt.Sprintf("spec/rules[%d]/when[%d]", ruleNum, i))
   118  			}
   119  		}
   120  	}
   121  	return len(paths) > 0, paths
   122  }
   123  
   124  func (c MtlsEnabledChecker) IsMtlsEnabledFor(labels labels.Set, namespace string) bool {
   125  	mtlsEnabledNamespaceLevel := c.hasMtlsEnabledForNamespace(namespace) == mtls.MTLSEnabled
   126  	if labels == nil {
   127  		return mtlsEnabledNamespaceLevel
   128  	}
   129  
   130  	workloadmTlsStatus := mtls.MtlsStatus{
   131  		AutoMtlsEnabled:     c.MtlsDetails.EnabledAutoMtls,
   132  		DestinationRules:    c.MtlsDetails.DestinationRules,
   133  		MatchingLabels:      labels,
   134  		PeerAuthentications: c.MtlsDetails.PeerAuthentications,
   135  		RegistryServices:    c.RegistryServices,
   136  	}.WorkloadMtlsStatus(namespace)
   137  
   138  	if workloadmTlsStatus == mtls.MTLSEnabled {
   139  		return true
   140  	} else if workloadmTlsStatus == mtls.MTLSDisabled {
   141  		return false
   142  	} else if workloadmTlsStatus == mtls.MTLSNotEnabled {
   143  		// need to check with ns-level and mesh-level status
   144  		return mtlsEnabledNamespaceLevel
   145  	}
   146  
   147  	return false
   148  }
   149  
   150  func (c MtlsEnabledChecker) hasMtlsEnabledForNamespace(namespace string) string {
   151  	mtlsStatus := mtls.MtlsStatus{
   152  		AutoMtlsEnabled: c.MtlsDetails.EnabledAutoMtls,
   153  	}.OverallMtlsStatus(c.namespaceMtlsStatus(namespace), c.meshWideMtlsStatus())
   154  
   155  	// If there isn't any PeerAuthn or DestinationRule and AutoMtls is enabled,
   156  	// then we can consider that the rule will be using mtls
   157  	// Masthead icon won't be present in this case.
   158  	if mtlsStatus == mtls.MTLSNotEnabled && c.MtlsDetails.EnabledAutoMtls {
   159  		mtlsStatus = mtls.MTLSEnabled
   160  	}
   161  
   162  	return mtlsStatus
   163  }
   164  
   165  func (c MtlsEnabledChecker) meshWideMtlsStatus() mtls.TlsStatus {
   166  	mtlsStatus := mtls.MtlsStatus{
   167  		PeerAuthentications: c.MtlsDetails.MeshPeerAuthentications,
   168  		DestinationRules:    c.MtlsDetails.DestinationRules,
   169  		AutoMtlsEnabled:     c.MtlsDetails.EnabledAutoMtls,
   170  		AllowPermissive:     true,
   171  	}
   172  
   173  	return mtlsStatus.MeshMtlsStatus()
   174  }
   175  
   176  func (c MtlsEnabledChecker) namespaceMtlsStatus(namespace string) mtls.TlsStatus {
   177  	mtlsStatus := mtls.MtlsStatus{
   178  		PeerAuthentications: c.MtlsDetails.PeerAuthentications,
   179  		DestinationRules:    c.MtlsDetails.DestinationRules,
   180  		AutoMtlsEnabled:     c.MtlsDetails.EnabledAutoMtls,
   181  		AllowPermissive:     true,
   182  	}
   183  
   184  	return mtlsStatus.NamespaceMtlsStatus(namespace)
   185  }