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 }