istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/grpc/tls.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package grpc 16 17 import ( 18 "crypto/tls" 19 "crypto/x509" 20 "fmt" 21 "net" 22 "os" 23 "strings" 24 25 "google.golang.org/grpc" 26 "google.golang.org/grpc/credentials" 27 28 "istio.io/istio/pkg/log" 29 sec_model "istio.io/istio/pkg/model" 30 "istio.io/istio/security/pkg/pki/util" 31 ) 32 33 // TLSOptions include TLS options that a grpc client uses to connect with server. 34 type TLSOptions struct { 35 RootCert string 36 Key string 37 Cert string 38 ServerAddress string 39 SAN string 40 } 41 42 func getTLSDialOption(opts *TLSOptions) (grpc.DialOption, error) { 43 rootCert, err := getRootCertificate(opts.RootCert) 44 if err != nil { 45 return nil, err 46 } 47 config := tls.Config{ 48 GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { 49 var certificate tls.Certificate 50 key, cert := opts.Key, opts.Cert 51 if key != "" && cert != "" { 52 isExpired, err := util.IsCertExpired(opts.Cert) 53 if err != nil { 54 log.Warnf("cannot parse the cert chain, using token instead: %v", err) 55 return &certificate, nil 56 } 57 if isExpired { 58 log.Warnf("cert expired, using token instead") 59 return &certificate, nil 60 } 61 // Load the certificate from disk 62 certificate, err = tls.LoadX509KeyPair(cert, key) 63 if err != nil { 64 return nil, err 65 } 66 } 67 return &certificate, nil 68 }, 69 RootCAs: rootCert, 70 MinVersion: tls.VersionTLS12, 71 } 72 73 if host, _, err := net.SplitHostPort(opts.ServerAddress); err == nil { 74 config.ServerName = host 75 } 76 // For debugging on localhost (with port forward) 77 if strings.Contains(config.ServerName, "localhost") { 78 config.ServerName = "istiod.istio-system.svc" 79 } 80 if opts.SAN != "" { 81 config.ServerName = opts.SAN 82 } 83 // Compliance for all gRPC clients (e.g. Citadel).. 84 sec_model.EnforceGoCompliance(&config) 85 transportCreds := credentials.NewTLS(&config) 86 return grpc.WithTransportCredentials(transportCreds), nil 87 } 88 89 func getRootCertificate(rootCertFile string) (*x509.CertPool, error) { 90 var certPool *x509.CertPool 91 var rootCert []byte 92 var err error 93 94 if rootCertFile != "" { 95 rootCert, err = os.ReadFile(rootCertFile) 96 if err != nil { 97 return nil, err 98 } 99 100 certPool = x509.NewCertPool() 101 ok := certPool.AppendCertsFromPEM(rootCert) 102 if !ok { 103 return nil, fmt.Errorf("failed to create TLS dial option with root certificates") 104 } 105 } else { 106 certPool, err = x509.SystemCertPool() 107 if err != nil { 108 return nil, err 109 } 110 } 111 return certPool, nil 112 }