| // Copyright Istio Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package gateway |
| |
| import ( |
| "istio.io/api/networking/v1alpha3" |
| ) |
| |
| import ( |
| "github.com/apache/dubbo-go-pixiu/pilot/pkg/features" |
| "github.com/apache/dubbo-go-pixiu/pkg/config/analysis" |
| "github.com/apache/dubbo-go-pixiu/pkg/config/analysis/analyzers/util" |
| "github.com/apache/dubbo-go-pixiu/pkg/config/analysis/msg" |
| "github.com/apache/dubbo-go-pixiu/pkg/config/resource" |
| "github.com/apache/dubbo-go-pixiu/pkg/config/schema/collection" |
| "github.com/apache/dubbo-go-pixiu/pkg/config/schema/collections" |
| ) |
| |
| type CertificateAnalyzer struct{} |
| |
| var _ analysis.Analyzer = &CertificateAnalyzer{} |
| |
| func (*CertificateAnalyzer) Metadata() analysis.Metadata { |
| return analysis.Metadata{ |
| Name: "gateway.CertificateAnalyzer", |
| Description: "Checks a gateway certificate", |
| Inputs: collection.Names{ |
| collections.IstioNetworkingV1Alpha3Gateways.Name(), |
| }, |
| } |
| } |
| |
| // Analyze implements analysis.Analyzer |
| func (gateway *CertificateAnalyzer) Analyze(context analysis.Context) { |
| context.ForEach(collections.IstioNetworkingV1Alpha3Gateways.Name(), func(resource *resource.Instance) bool { |
| gateway.analyzeDuplicateCertificate(resource, context, features.ScopeGatewayToNamespace) |
| return true |
| }) |
| } |
| |
| func (gateway *CertificateAnalyzer) analyzeDuplicateCertificate(currentResource *resource.Instance, context analysis.Context, scopeGatewayToNamespace bool) { |
| currentGateway := currentResource.Message.(*v1alpha3.Gateway) |
| currentGatewayFullName := currentResource.Metadata.FullName |
| gateways := getGatewaysWithSelector(context, scopeGatewayToNamespace, currentGatewayFullName, currentGateway.Selector) |
| |
| for _, gatewayFullName := range gateways { |
| // ignore matching the same exact gateway |
| if currentGatewayFullName == gatewayFullName { |
| continue |
| } |
| |
| gatewayInstance := context.Find(collections.IstioNetworkingV1Alpha3Gateways.Name(), gatewayFullName) |
| gateway := gatewayInstance.Message.(*v1alpha3.Gateway) |
| for _, currentServer := range currentGateway.Servers { |
| for _, server := range gateway.Servers { |
| // make sure have TLS configuration |
| if currentServer.Tls == nil || server.Tls == nil { |
| continue |
| } |
| |
| if haveSameCertificate(currentServer.Tls, server.Tls) { |
| gatewayNames := []string{currentGatewayFullName.String(), gatewayFullName.String()} |
| message := msg.NewGatewayDuplicateCertificate(currentResource, gatewayNames) |
| |
| if line, ok := util.ErrorLine(currentResource, util.MetadataName); ok { |
| message.Line = line |
| } |
| |
| context.Report(collections.IstioNetworkingV1Alpha3Gateways.Name(), message) |
| } |
| } |
| } |
| } |
| } |
| |
| func haveSameCertificate(currentGatewayTLS, gatewayTLS *v1alpha3.ServerTLSSettings) bool { |
| if currentGatewayTLS.CredentialName != "" && gatewayTLS.CredentialName != "" { |
| return currentGatewayTLS.CredentialName == gatewayTLS.CredentialName |
| } |
| |
| if currentGatewayTLS.CredentialName == "" && gatewayTLS.CredentialName == "" { |
| if currentGatewayTLS.ServerCertificate != "" && gatewayTLS.ServerCertificate != "" { |
| if currentGatewayTLS.ServerCertificate == gatewayTLS.ServerCertificate { |
| if currentGatewayTLS.PrivateKey != "" && gatewayTLS.PrivateKey != "" { |
| return currentGatewayTLS.PrivateKey == gatewayTLS.PrivateKey |
| } |
| return false |
| } |
| } |
| } |
| |
| return false |
| } |
| |
| // get all gateways that is superset of the selector |
| func getGatewaysWithSelector(c analysis.Context, gwScope bool, currentGWName resource.FullName, currentGWSelector map[string]string) []resource.FullName { |
| var gateways []resource.FullName |
| |
| c.ForEach(collections.IstioNetworkingV1Alpha3Gateways.Name(), func(resource *resource.Instance) bool { |
| // if scopeToNamespace true, ignore adding gateways from other namespace |
| if gwScope { |
| if currentGWName.Namespace != resource.Metadata.FullName.Namespace { |
| return true |
| } |
| } |
| |
| // if current gateway selector is empty, match all gateway |
| if len(currentGWSelector) == 0 { |
| gateways = append(gateways, resource.Metadata.FullName) |
| return true |
| } |
| |
| gateway := resource.Message.(*v1alpha3.Gateway) |
| // if current gateway selector is subset of other gateway selector |
| // add other gateway |
| if selectorSubset(currentGWSelector, gateway.Selector) { |
| gateways = append(gateways, resource.Metadata.FullName) |
| } |
| |
| return true |
| }) |
| |
| return gateways |
| } |
| |
| func selectorSubset(selectorX, selectorY map[string]string) bool { |
| var count int |
| |
| for keyX, valueX := range selectorX { |
| for keyY, valueY := range selectorY { |
| if keyX == keyY { |
| // if have same key but different value |
| // mean selectorX is not subset of selectorY |
| if valueX != valueY { |
| return false |
| } |
| // if key and value is same |
| // increase the counting |
| count++ |
| } |
| } |
| } |
| |
| // if total counting is not same with the length |
| // of selectorX, selectorX is not subset of selectorY |
| return count == len(selectorX) |
| } |