istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/xds/client.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 xds 16 17 // xds uses ADSC to call XDS 18 19 import ( 20 "context" 21 "crypto/tls" 22 "fmt" 23 "strings" 24 25 discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 26 "google.golang.org/grpc" 27 "google.golang.org/grpc/credentials" 28 29 "istio.io/istio/istioctl/pkg/clioptions" 30 "istio.io/istio/pilot/pkg/model" 31 "istio.io/istio/pkg/adsc" 32 "istio.io/istio/pkg/kube" 33 ) 34 35 const ( 36 // defaultExpirationSeconds is how long-lived a token to request (an hour) 37 defaultExpirationSeconds = 60 * 60 38 ) 39 40 // Audience to create tokens for 41 var tokenAudiences = []string{"istio-ca"} 42 43 // GetXdsResponse opens a gRPC connection to opts.xds and waits for a single response 44 func GetXdsResponse(dr *discovery.DiscoveryRequest, ns string, serviceAccount string, opts clioptions.CentralControlPlaneOptions, 45 grpcOpts []grpc.DialOption, 46 ) (*discovery.DiscoveryResponse, error) { 47 adscConn, err := adsc.NewWithBackoffPolicy(opts.Xds, &adsc.ADSConfig{ 48 Config: adsc.Config{ 49 Meta: model.NodeMetadata{ 50 Generator: "event", 51 ServiceAccount: serviceAccount, 52 Namespace: ns, 53 CloudrunAddr: opts.IstiodAddr, 54 }.ToStruct(), 55 CertDir: opts.CertDir, 56 InsecureSkipVerify: opts.InsecureSkipVerify, 57 XDSSAN: opts.XDSSAN, 58 GrpcOpts: grpcOpts, 59 }, 60 }, nil) 61 if err != nil { 62 return nil, fmt.Errorf("could not dial: %w", err) 63 } 64 err = adscConn.Run() 65 if err != nil { 66 return nil, fmt.Errorf("ADSC: failed running %v", err) 67 } 68 69 err = adscConn.Send(dr) 70 if err != nil { 71 return nil, err 72 } 73 response, err := adscConn.WaitVersion(opts.Timeout, dr.TypeUrl, "") 74 return response, err 75 } 76 77 // DialOptions constructs gRPC dial options from command line configuration 78 func DialOptions(opts clioptions.CentralControlPlaneOptions, 79 ns, serviceAccount string, kubeClient kube.CLIClient, 80 ) ([]grpc.DialOption, error) { 81 ctx := context.TODO() 82 // If we are using the insecure 15010 don't bother getting a token 83 if opts.Plaintext || opts.CertDir != "" { 84 return make([]grpc.DialOption, 0), nil 85 } 86 // Use bearer token 87 aud := tokenAudiences 88 isMCP := strings.HasSuffix(opts.Xds, ".googleapis.com") || strings.HasSuffix(opts.Xds, ".googleapis.com:443") 89 if isMCP { 90 // Special credentials handling when using ASM Managed Control Plane. 91 mem, err := getHubMembership(ctx, kubeClient) 92 if err != nil { 93 return nil, fmt.Errorf("failed to query Hub membership: %w", err) 94 } 95 aud = []string{mem.WorkloadIdentityPool} 96 } 97 k8sCreds, err := kubeClient.CreatePerRPCCredentials(ctx, ns, serviceAccount, aud, defaultExpirationSeconds) 98 if err != nil { 99 return nil, fmt.Errorf("failed to create RPC credentials for \"%s.%s\": %w", serviceAccount, ns, err) 100 } 101 if isMCP { 102 return mcpDialOptions(ctx, opts.GCPProject, k8sCreds) 103 } 104 return []grpc.DialOption{ 105 // nolint: gosec 106 // Only runs over istioctl experimental 107 // TODO: https://github.com/istio/istio/issues/41937 108 grpc.WithTransportCredentials(credentials.NewTLS( 109 &tls.Config{ 110 // Always skip verifying, because without it we always get "certificate signed by unknown authority". 111 // We don't set the XDSSAN for the same reason. 112 InsecureSkipVerify: true, 113 })), 114 grpc.WithPerRPCCredentials(k8sCreds), 115 }, nil 116 }